JS中的call(), apply()和bind()
intro
在函数内部,根据是否是严格模式(strict mode)
,this
指向undefined
或window
。
但是,可以手动指定this
的绑定|指向。
调用函数时,要指定函数的this
指向那个对象,可以用Function
函数对象的apply()
,他接收两个参数:需要绑定的this
变量,函数参数列表的数组形式argArray
。
demo
- 换绑定
Function对象
内部的this指向。
// 用于返回Person对象。
function getPerson(name, age) {
let obj = new Object();
obj.name = name;
obj.age = age;
obj.show = function() {
console.log(this.name + "\t" + this.age);
}
return obj;
}
// 实例化p1和p2
var p1 = getPerson("aaa", 11);
var p2 = getPerson("bbb", 22);
// 两个对象各自调用show()
p1.show();
p2.show();
// 用p1调用show()方法,但换绑定内部的this为p2。
p1.show.apply(p2);
输出:
// 用于返回Person对象。
function getPerson(name, age) {
let obj = new Object();
obj.name = name;
obj.age = age;
obj.show = function() {
console.log(this.name + "\t" + this.age);
}
return obj;
}
undefined
// 实例化p1和p2
var p1 = getPerson("aaa", 11);
var p2 = getPerson("bbb", 22);
undefined
// 两个对象各自调用show()
p1.show();
p2.show();
aaa 11
bbb 22
undefined
// 用p1调用show()方法,但换绑定内部的this为p2。
p1.show.apply(p2);
bbb 22
undefined
- 不换绑
Function对象
内部的this
。
Math.max(2, 5, 3);
5
Math.max.apply(null, 2, 5, 3); // thisArg处传入null。
5
另有func.call()
和func.bind()
方法。
Math.max.call(null, 2, 5)
5
Math.max.bind(null)(2, 5); // func.bind()返回一个新的Function对象。Function对象的调用:函数名(...args)。
5
函数声明
func.apply(thisArg, ?argArray)
在一个对象的上下文中应用另一个对象的方法。参数以Array
数组格式传入。
func.call(thisArg, ...argsList)
同call()
,参数以列表形式传入。
func.bind(thisArg, ...argsList) - Function
thisArg
要换绑定的this新值(不换可传入null)。
argArray
向函数传入的参数数组(Array格式)。
...argsList
向函数传入的参数列表(用到了ES6
的...rest参数(展开运算符)
)。
bind()
方法会创建一个新函数,称为绑定函数
。
当调用这个绑定函数时,绑定函数会以创建它时传入的第一个参数thisArg
作为this
,
以传入bind()
中的其余参数再加上绑定函数运行时本身传入的参数按照顺序作为原型函数的参数来调用原函数。
比较
-
第一个参数
三个方法的第一个参数都是要换绑定的this参数thisArg
如果不需要换绑定则传入null
。 -
第二个参数
apply()
的第二个参数是?argArray
,是参数列表的数组格式(一个Array
对象)。
而call()
和bind()
的第二个参数都是...argsList
(用到了ES6
的新特性...rest参数(展开运算符)
)。 -
函数返回值。
apply()
和call()
的函数返回值都是根据其caller
函数的返回值决定的。
而bind()
返回一个Function对象
(经过修改后的新的方法)。
调用Function对象
:funcName(...argsList)
。
应用
动态修改函数内部this绑定的对象
- 查看
object
的具体类型
arr = [1,2,3]; // Array类型也是object类型。用typeof检测不够精细。
// 换绑定 Object.prototype.toString() 函数内部的this。
Object.prototype.toString.apply(arr);
Object.prototype.toString.call(arr);
Object.prototyupe.toString.bind(arr)();
- 装饰器(动态修改函数功能)
利用apply()
动态改变函数的行为(以及call()
或bind()
)。
JS中所有对象都是动态的,即使内置的函数,也可以重新指向新的函数。
如:统计代码中调用了多少次 window.parseInt()
。
var invokeCount = 0; // 初始化调用次数
var tmpParseInt = window.parseInt; // 暂存原函数
// 覆盖同名的全局变量`parseInt`
window.parseInt = function() {
invokeCount += 1; // 调用次数+1
return tmpParseInt.apply(null, arguments); // 调用原函数
}
// 测试
console.log(invokeCount); // 0
window.parseInt("10");
window.parseInt("2.22");
window.parseInt(false);
console.log(invokeCount); // 3
window.parseInt = tmpParseInt; // 还原
- 其他(需要动态修改函数内部this绑定的对象)。