博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
回首向来萧瑟处,归去,也无风雨也无晴 — call、apply和bind
阅读量:5930 次
发布时间:2019-06-19

本文共 4119 字,大约阅读时间需要 13 分钟。

  hot3.png

授业至今,技艺日有进益,许是看的多了,先时似是而非的东西,今时也多有顿悟,call和apply学的早,用得少,同是作用于this,bind就用的多,但这个函数扩展方法是ECMAscript5里的,IE[6-8]不支持,移动端可以放心用,这里说与某家主公知道。

this之于call、apply和bind,五花肉之于东坡肉、红烧肉和回锅肉,反复思量,深感经世以来比喻之周全者未有过于此者。因其关键,蒙师授业之初费了大周折讲它,终了一句话“.前头谁调用,this就是谁,没有.前头,就是window”醍醐灌顶。

js中this总是指向一个对象,情况有4种                                                                                  

1、作为对象的方法调用

var persion = {	name : "haha",	getName : function(){		console.log(this === persion);//true		console.log(this.name);//"haha"	}};persion.getName();

2、作为普通函数调用

此时this总是指向全局对象window

window.name = "global";	var getName = function(){	return this.name;}console.log(getName());//"global"

或者

window.name = "global";var persion = {	name : "haha",	getName : function(){		return this.name;	}}console.log(persion.getName());//"haha"var getName = persion.getName;console.log(getName());//"global"

DOM节点的事件函数内部,有个局部的callback方法,callback被当做普通函数调用时,callback内部的this指向了window,但是我们想让它指向该DOM节点

document.getElementById("btn").onclick = function(){	console.log(this.id)//"btn"	var callback = function(){        console.log(this) //window		console.log(this.id) //undefined	}	callback();}

常用的解决方案

document.getElementById("btn").onclick = function(){	console.log(this.id)//"btn"	var that = this;	var callback = function(){		console.log(that.id)//"btn"	}	callback();}

在ECMAScript5的strict严格模式下

document.getElementById("btn").onclick = function(){    "use strict"	console.log(this.id)//"btn"	var callback = function(){        console.log(this) //undefined		console.log(this.id) //undefined	}	callback();}

strict这种模式多余的很

3、构造器调用

js函数大多数都可以当做构造器使用,当用new 运算符调用函数时,该函数总会返回一个对象,通常情况下,构造器里的this就指向返回的这个对象

var Persion = function(){	this.name = "haha";}var persion1 = new Persion();console.log(persion1.name);//"haha"

用new调用构造器时,如果构造器显式地返回了一个object类型的对象,那么运行的结果就是返回的这个对象,不是之前期待的那个this

var Persion = function(){	this.name = "haha";	return {		name : "hehe"	}}var persion1 = new Persion();console.log(persion1.name);//"hehe"

构造器不显式返回数据或者返回非对象类型的数据,不会造成上述问题

var Persion = function(){	this.name = "haha";	return  "hehe";}var persion1 = new Persion();console.log(persion1.name);//"haha"

4、call和apply调用

call和apply可以动态地改变传入函数的this

var persion1 = {	name : "haha",	getName : function(){		console.log(this.name + " from persion1");	}};var persion2 = {	name : "hehe",	getName : function(){		console.log(this.name + " from persion2");	}};console.log(persion1.getName.call(persion2));// "hehe from persion2"

call和apply

call和apply都是改变this指向,区别在于参数传入的形式不同

var func = function(a,b,c){	console.log([a,b,c]);//[1,2,3]}func.call(null,1,2,3);func.apply(null,[1,2,3]);

call和apply第一个参数传入的都是函数体内的this指向,不同在于call第二参数往后依次传入与函数体形参相对应的实参,apply第二个参数是一个实参数组,数组中的元素同样与函数体的形参相对应。

孰用孰不用,有一种说法apply比call的使用效率更高,因为在js的参数在内部就是用一个数组来表示的,用arguments可以访问到。

使用call和apply的时候传入的第一个参数是null,函数执行的时候this会指向默认的宿主对象,也就是window。

var func = function(a,b,c){	console.log(this === window);//true}func.call(null,1,2,3);

严格模式下情况就不一样了

var func = function(a,b,c){	console.log(this === null);//true}func.call(null,1,2,3);

它们的用途

1、改变this指向

var persion1 = {	name : "haha",	getName : function(){		console.log(this.name + " from persion1");	}};var persion2 = {	name : "hehe",	getName : function(){		console.log(this.name + " from persion2");	}};console.log(persion1.getName.call(persion2));// "hehe from persion2"

一样的代码再来一遍

2、模拟bind方法

bind方法低级浏览器里没有,但可以用apply来封装

Function.prototype.bind = function(context){	var self = this;	return function(){		return self.apply(context,arguments);	}}var obj = {	name:"haha"}var getName = function(){	console.log(this.name);//"haha"}.bind(obj);

3、借用其他对象方法

var A = function(name){	this.name = name;}var B = function(){	A.apply(this,arguments);}B.prototype.getName = function(){	return this.name;}var b = new B('hehe');console.log(b.getName());//"hehe"

上面是的场景是“借用构造函数”,通过这种技术,可以实现出类似继承的效果,此外还有一种借用场景

(function(){	Array.prototype.push.apply(arguments,3);	console.log(arguments);//[1,2,3]})(1,2)

函数的参数列表arguments是一个类数组

(function(){	console.log(typeof arguments);//object	Array.prototype.push.call(arguments,3);	console.log(arguments);//[1,2,3]})(1,2)

本身不具备push方法,可以使用call或apply借用Array.prototype对象的方法,前提是借用方法的对象要可以存取属性、length属性可读写

《JavaScript设计模式与开发实践》是本好书

 

 

转载于:https://my.oschina.net/iamllb/blog/736360

你可能感兴趣的文章
PHP判断访问者手机移动端还是PC端的函数
查看>>
【Cg语言学习】开始Cg之旅,编译自己的第一个Cg程序
查看>>
ES6学习笔记
查看>>
Python 字符串
查看>>
hdu 5340 (manacher)
查看>>
C++Primer学习——类
查看>>
KMP算法学习&总结
查看>>
JS总结
查看>>
leetcode Valid Sudoku
查看>>
JAVA连接数据库后,对数据库进行增删改查
查看>>
Ubuntu 安装Samba服务器
查看>>
PHP多进程系列笔记(二)
查看>>
PAT 1051 Pop Sequence[栈][难]
查看>>
C 语言学习 -1
查看>>
从GIMP的Retinex算法里发现了一种高斯模糊的快速实现方法【开发记录】。
查看>>
linux 下su 和sudo 的用法以及区别
查看>>
类的继承
查看>>
Flask 第五篇 用户登录
查看>>
NOIP2016提高组初赛Pascal模拟试题参考答案(可能有误)
查看>>
unicode和utf-8的区别
查看>>