call, apply, bind

call

MDN上的解释:

call() 方法调用一个函数, 其具有一个指定的this值和分别地提供的参数(参数的列表)。
简单理解就是call改变了函数内部的this指向。
语法:

1
fun.call(thisArg, arg1, arg2, ...)

thisArg:在fun函数运行时指定的this值。(如果传入的是null或者undefined,在非严格模式下,this会指向全局对象;如果传入的是原始数据类型的值,this会指向该值的自动包装类型。)
arg1, arg2, ...:参数列表。

示例:

1
2
3
4
5
6
7
8
9
10
11
var obj = {
a: 1,
getA: function (param1, param2) {
console.log('this.a:' + this.a + '; param1:' + param1 + '; param2:' + param2);
}
}
obj.getA(2, 3); // this.a:1; param1:2; param2:3
newObj = {
a: 2
}
obj.getA.call(newObj, 2, 3); // this.a:2; param1:2; param2:3

obj.getA(...)this指向obj,所以this.a === obj.a === 1;
obj.getA.call(newObj,...)this指向newObj,所以this.a === newObj.a ===2;

apply

MDN上的解释:

apply() 方法调用一个函数, 其具有一个指定的this值,以及作为一个数组(或类数组的对象)提供的参数。

1
func.apply(thisArg, argsArray)

thisArg:可选。在fun函数运行时指定的this值。(如果传入的是null或者undefined,在非严格模式下,this会指向全局对象;如果传入的是原始数据类型的值,this会指向该值的自动包装类型。)
argsArray:可选。一个数组或者类数组对象,其中的数组元素将作为单独的参数传给func函数。如果该参数的值为nullundefined,则表示不需要传入任何参数。

applycall函数具有相同的功能,唯一的不同是传入参数的方式:call方法中参数是以参数列表的形式(也就是多个参数)传入;apply方法中参数是以数据的形式传入。
示例:

1
2
3
4
5
6
7
8
9
10
11
12
var obj = {
a: 1,
getA: function (param1, param2) {
console.log('this.a:' + this.a + '; param1:' + param1 + '; param2:' + param2);
}
}
obj.getA(2, 3); // this.a:1; param1:2; param2:3
newObj = {
a: 2
}
obj.getA.call(newObj, 2, 3); // this.a:2; param1:2; param2:3
obj.getA.apply(newObj, [2, 3]); // this.a:2; param1:2; param2:3

obj.getA(...)this指向obj,所以this.a === obj.a === 1;
obj.getA.apply(newObj,...)this指向newObj,所以this.a === newObj.a ===2;

bind

MDN上的解释:

bind()方法创建一个新的函数, 当被调用时,将其this关键字设置为提供的值,在调用新函数时,在任何提供之前提供一个给定的参数序列。

1
func.bind(thisArg, arg1, arg2, ...)

thisArg:可选。当func函数被调用时,该参数会作为原函数运行时的this指向。当使用new操作符调用绑定函数时,该参数无效。
arg1, arg2, ...:可选。参数列表

bindcall函数具有类似的功能,不同的是bind不会立即执行函数,而是将函数返回(该函数包含了新的this指向和给定的参数)。
示例:

1
2
3
4
5
6
7
8
9
10
11
12
var obj = {
a: 1,
getA: function (param1, param2) {
console.log('this.a:' + this.a + '; param1:' + param1 + '; param2:' + param2);
}
}
obj.getA(2, 3); // this.a:1; param1:2; param2:3
newObj = {
a: 2
}
var bindGetA=obj.getA.bind(newObj, 2, 3);
bindGetA(); // this.a:2; param1:2; param2

bindcall/apply另一个不同在于bind中绑定的thisArg并不总是有效,正如前文介绍thisArg时提到的:

当使用new操作符调用绑定函数时,该参数无效。
来看一个示例:

1
2
3
4
5
6
7
8
9
10
11
function test() {
this.a = 1;
}
let t = new test();
console.log(t.a); // 1
const obj = {
a: 2
}
let bindTest = test.bind(obj);
let t2 = new bindTest();
console.log(t2.a); // 1

bindTest中绑定了obj,然而在用new生成实例的过程中,this的指向依然是t2,所以,在使用new生成实例时,thisarg参数无效。