小知识,大挑战!本文正在参与“程序员必备小知识”创作活动。
前言
我们之前提到了函数动态this的特性,改变this的方法和锁定this的方法。
今天我们继续介绍 改变this方法的call, apply, bind.
call
参数
function.call(thisArg, arg1, arg2, ...)
- thisArg
函数运行时使用的this值 - arg1, arg2, ...
其他参数
来看一个sum的方法:
function sum(num1, num2){
return (num1 + num2) * this.rate
}
sum.call({rate:1.5}, 100, 200)
// 450
看看第一个参数传null:
function sum(num1, num2){
return (num1 + num2) * this.rate
}
sum.call(null, 100, 200)
// NaN
再看看严格模式null:
"use strict"
function sum(num1, num2){
return (num1 + num2) * this.rate
}
sum.call( null, 100, 200)
// VM1673:3 Uncaught TypeError: Cannot read properties of null (reading 'rate')
sum.call( undefined, 100, 200)
// VM1673:3 Uncaught TypeError: Cannot read properties of undefined (reading 'rate')
严格模式下, null和undefined是不会被包装的。
相反的,非严格模式下,非引用数据类型会被包装为对象。
function log(){
console.log(this)
}
log.call(1)
// Number {1}
log.call(false)
// Boolean {false}
log.call("")
// String {''}
可能你到这里觉得很简单,我们看一道题:
function a(){
console.log(this,'a')
};
function b(){
console.log(this,'b')
}
a.call.call(b,'b')
a.call.call.call(b,'b')
a.call.call.call.call(b,'b')
apply
appy和call非常的类似,除了第一个参数意外的参数,是以数组的形式传递的。
function sum(num1, num2){
return num1 + num2
}
sum.apply(null, [1,2]);
// 3
后来,我看nodejsevents模块的源码时候发现, 再执行函数调用的时候,对四个参数以内的调用都是使用call,而不是简单粗暴的使用apply, 后来一查,原来有call的性能高于apply的说法。 我们今天就一起来验证一下:
function sum(){
return arguments.length
}
console.time("call")
for(let i=0; i< 10000000; i++){
sum.call(null, 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20)
}
console.timeEnd("call")
console.time("apply")
for(let i=0; i< 10000000; i++){
sum.apply(null, [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20])
}
console.timeEnd("apply")
// call: 111.688232421875 ms
// apply: 154.789794921875 ms
// call: 114.31103515625 ms
// apply: 157.2490234375 ms
// call: 113.232177734375 ms
// apply: 160.802978515625 ms
循环次数,1万以内都不明显, 1000万后,还是比较明显的。
bind
bind和上面两个就有些区别得了,其返回的是一个函数,还可以提前绑定参数,非常的强大,比起用闭包来复用,我更喜欢这款。
function multi(a, b){
return a*b
}
function getDoubleFunction(multiple){
return multi.bind(null, multiple)
}
const m100 = getDoubleFunction(100)(100);
m100(10)
// 1000
const m15 = getDoubleFunction(100);
m15(10)
// 150
还有一点就是多次bind,第一个bind的this生效。
function log(){
console.log(this);
}
log.bind({a:1}).bind({a:2})();
// {a:2}
小结
今天你收获了吗?
引用
call, call.call, call.call.call, 你也许还不懂这疯狂的call
call和apply的性能对比