三兄弟来源
call,apply,bind 为什么要叫做三兄弟,是因为他们有一个共同的父亲——Function.prototype,所以他们都是实例方法,不妨咱们现场"滴血认亲"一下
Function.prototype.hasOwnProperty('call');
Function.prototype.hasOwnProperty('apply');
Function.prototype.hasOwnProperty('bind');
上面三条语句的返回结果都为true,算了有图有真相,上图

因此,这三兄弟可以在对象,数组,函数中都可以使用。
大哥——Call
call方法,可以指定所用目标函数的this指向,即函数执行时所在的作用域(上下文),并且在指定的作用域调用这个函数,立即执行。
var content = {
number: 2
};
var number = 1;
function func(){
console.log(this.number);
}
a(); //结果为1
a.call(); //没有传递参数还是默认所在的作用域
a.call(content); //指向content的内部作用域,此时结果为2
即,当我们执行a函数时,它指向的是全局对象,所以this指向的也就是全局对象;但当我们帮它指向content对象时,这个函数的执行作用域也就变为了content对象的作用域
Call 传参
call方法可以传递多个参数,第一个参数即为指定的this的指向,即要提供这个函数要执行所存在的作用域的家伙,后面的参数是函数调用时需要使用的参数,直接用","号分割即可。
如果 call的第一个参数为null或者undefined或者this,它等同于指向全局对象。
二哥——Apply
apply方法身为二哥,自然是和大哥的作用非常相似,他们都是改变this指向来在制定的作用域中调用这个函数,立即执行,唯一的不同可能就是二哥Apply相比较于大哥Call来说它更"挑食"。它只能接收两个参数,第一个参数为this指向的对象,第二个参数为执行时需要的参数,注意,它只要数组作为他的第二个参数。
我们让大哥和二哥实现相同的功能来看一下他们的不同
function sum(a,b){
return a + b;
}
sum.call(this,1,2); //结果为3
sum.apply(this,[1,2]); //结果为3
所以,当我们要让某个数组来执行某种方法时,使用apply方法相较于call方法能方便很多。比如我们想快速的查找一个数组中的最大值
var a = [1,2,3,4,5,7,8,9,45,123,111];
Math.max.apply(this,a); // 123
三弟——bind
bind方法用于指定函数内部的this指向,然后返回一个新函数,但它不会立即执行,它只是给这个函数增加了修饰,并没有调用它。
var content = {
number: 2
};
function func(){
console.log(this.number);
}
//call方法
func.call(content); // 2
//apply方法
func.apply(content); //2
//bind方法
func.bind(content)(); //2
bind的参数要求和大哥一样,即为一个一个的传参.
call 和 apply 方法在调用后会立即执行,而bind则是把作用域修改后的函数返回,需要自己再次手动调用。
三兄弟异同
从上面的例子我们可以看到三兄弟十分相似,但也各有千秋。
同:
- 都用来改变函数的this指向,即作用域。
- 第一个参数都是用来指定函数内部的this。
- 都可以在函数调用的时候传递原函数所需要的参数。
异:
- call 和 apply 调用后立即执行,而bind则是把新函数返回,需要再次调用。
- call 和 bind 传递参数是直接传入,也就是一个一个的传,而apply 则需要一个数组来作为第二个参数。