what's call、apply、bind?

hello,各位,今天是年三十,本来呢是想好好过个新年的,去看看什么春晚呀,可是发现春晚是在是不合胃口。今年支付宝,微信,QQ齐出大招,各种红包雨。支付宝的拼命咻,微信的摇断手,QQ的刷啊刷。本宝宝弄了一两轮就累得不行TAT,各大互联网真心有料,今年做得还是挺不错的。

所以就进来房间来倒腾一下。虽然时间也不早了,我看看能写多少就写多少吧~~
在这里先给大家拜个早年~~猴年行大运,恭喜发财呀~

BB了好多有的没的。现在正式进入正题

call()、apply()、bind()是干什么的

其实之前学这些的时候,总是学完就好快忘了,深究原因,还是没有理解透彻,首先他们用在哪个地方呢?这个好像我并没有很深去思考。
那么问题来了,现在就让我来给大家说说,这几个函数是用来做啥的。
在回答这个问题前,咱们先花点时间看下这一段代码

1
2
3
4
5
6
7
8
9
10
11
12
function Demo1(name){
this.name = name;
this.sayHi = function(){
alert(this.name);
}
}

function Demo2(){

};
var demo = new Demo2();
demo.sayHi();//Uncaught TypeError: demo.sayHi is not a function(…)

可能这个问题有点小儿科,这段代码的执行结果是一个错误,提示没有在Demo2上找到sayHi方法。

那么好,我们稍微修改一下代码,只要修改点点即可:

1
2
3
4
5
6
7
8
9
10
11
12
function Demo1(name){
this.name = name;
this.sayHi = function(){
alert(this.name);
}
}

function Demo2(){
Demo1.call(this,"zyy")
};
var demo = new Demo2();
demo.sayHi();//弹出“zyy”

只有一句代码:Demo1.call(this),我们就可以在Demo2上使用Demo1上定义的方法,是不是很神奇,这种方法叫做继承。所以也就理解call()、apply()与bind()是干什么的了。

区别

我们知道call、apply与bind都是属于Function.prototype上的方法
可以用来改变函数的执行上下文,最明显的就是改变函数体内部this的指向。

在JavaScript中, 函数的执行上下文(函数作用域)分为两种,定义时上下文,调用时上下文,而且函数的执行上下文是可以被改变的。

call与apply的异同:

  • 相同点
    作用都是一样的,动态修改函数的执行上下文,调用被改变上下文函数对象的方法。
  • 不同点
    传入的参数不同

注:非严格模式下, 在全局的话 this指向window或global,如果call,apply或bind的第一个参数是undefined或 null 都是指向window或global。

由上可知在函数的参数个数确定的情况下两者是没什么差别的,如果参数个数不确定,就选择用apply。

通过改变上下文我们就可以调用函数或对象的内置方法,举例:

1
2
var arr = [2,5,6,2,11,51];
var maxNum = Math.max.apply(Math,arr); //51
1
2
3
4
//Object的内置方法 toString返回一个类型字符串
Object.prototype.toString.call(Math); //"[object Math]"
Object.prototype.toString.apply(Math); //"[object Math]"
typeof Math //"object"

bind又是什么呢?

bind的作用和apply与call的很相似

MDN的解释是:bind()方法会创建一个新函数,称为绑定函数,当调用这个绑定函数时,绑定函数会以创建它时传入 bind()方法的第一个参数作为 this(改变函数的执行上下文),传入 bind() 方法的第二个以及以后的参数加上绑定函数运行时本身的参数按照顺序作为原函数的参数来调用原函数。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
var num = 6;
var foo = {
num:66,
getNum :function(){
return this.num;
}
};
//对象.调用时,this指向对象
foo.getNum(); //66

var getNum = foo.getNum;
//全局下调用,等于价与下面这段
var getNum = function(){
return this.num;
}
getNum();

//创建一个‘this’绑定到对象 foo 的函数
var bindGetNum = getNum.bind(foo);
bindGetNum(); //66

在异步回调函数中, 比如setTimeout ,this指向window或global对象。当使用类的方法时需要this指向类实例,就可以使用bind()将this绑定到回调函数来管理实例。

bind特性, 偏函数(预定义参数): 使用bind()我们设定函数的预定义参数,然后调用的时候传入其他参数即可

bind()函数是在 ECMA-262 第五版(ES5)才被加入,所以要兼容IE8一下的就要自己实现bind函数了

1
2
3
4
5
6
Function.prototype.bind = function(context){
self = this; //保存this,即调用bind方法的目标函数
returnfunction(){
return self.apply(context,arguments);
};
};

或者(可以绑定对象,也支持在绑定的时候传参):

1
2
3
4
5
6
7
8
9
Function.prototype.bind = function(context){
var args = Array.prototype.slice.call(arguments, 1),
self = this;
returnfunction(){
var innerArgs = Array.prototype.slice.call(arguments);
var finalArgs = args.concat(innerArgs);
return self.apply(context,finalArgs);
};
};

总结一下:

  • apply 、 call 、bind 三者都是用来改变函数的this对象的指向的;
  • apply 、 call 、bind 三者第一个参数都是this要指向的对象,也就是想指定的上下文;
  • apply 、 call 、bind 三者都可以利用后续参数传参;
  • bind 是返回对应函数,便于稍后调用;apply 、call 则是立即调用 。
# js

评论

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×