call的作用
一句话:改变调用方法的this指向,示例如下:
function a(){
console.log(this);
}
a();
a.call({name:"西瓜"});

可以看到,第一次this
指向了window
,第二次this
指向了传入的对象;
那么在执行call方法的时候,内部做了什么处理呢?
先来看一个东西,或许就能明白
var a = {
name:"西瓜",
run:function(){
console.log(this);
console.log(this.name);
}
}
a.run();

上面这段代码,相信小伙伴都能看懂,其实,call执行的时候,也是做了这样的处理;。
手动来实现一个call
Function.prototype.MyCall = function(obj){
var newObj = obj || window;
newObj.fn = this;
var params = [...arguments].slice(1);
var result = newObj.fn(...params);
delete newObj.fn;
return result;
}
就上面的这段代码,就实现了一个call的功能,来看下这段代码都做了哪些事情
- 定义一个新的对象,若传入的
obj
存在,则新对象等于obj
,若obj
不存在,则等于window
; - 把this挂在到当前定义的新对象上(this即为调用的函数);
- 第4行代码处理了函数的传参;
- 然后执行创建的新对象的
fn
函数(即为要调用的函数); - 最后在执行了以后,把这个挂载的
fn
删除;
来验证一下是否正确
function test(){
console.log(this);
}
test();
test.MyCall({name:"西瓜"});
结果如下图:

接下来,讲一个我在学习call的时候,网上经常讲到的一个案例,我们一起来看一下:
function f1(a){
console.log(1);
console.log(this);
}
function f2(){
console.log(2);
console.log(this);
}
f1.call(f2);
f1.call.call(f2);
想一下,这段代码打印出来的会是一个什么结果呢?

f1.call(f2)
的打印结果,相信大家都能理解,这里就不解释了;重点来讲一下f1.call.call(f2)
;
首先,我们用刚刚自己实现的call方法来试试,会不会出现同样的结果;
f1.MyCall(f2);
f1.MyCall.MyCall(f2);
结果当然是一样的啦!如下:

Function.prototype.MyCall = function(obj){
var newObj = obj || window;
newObj.fn = this;
var params = [...arguments].slice(1);
var result = newObj.fn(...params);
delete newObj.fn;
return result;
}
当我们执行f1.MyCall.MyCall(f2)
的时候,上面这个MyCall
方法中的this
和newObj
指的分别是什么?
我的理解是this
为f1.MyCall
,即为Function.prototype.MyCall
,newObj
为f2
方法;
所当f1.MyCall.MyCall(f2)
执行的时候,结果就变了以下结果:
var newObj = f2;
f2.fn = Function.prototype.MyCall;
接下来MyCall
的第5行是不是会执行newObj.fn
?
其实就是执行f2.MyCall()
这个结果大家应该都知道了吧;
如果说上面这个理解了,可以想想下面几个会打印出什么内容:
f1.call.call.call(f2)
f1.call.call.call.call(f2)
f1.call.call.call.call.call(f2)
其实都是一样的哈!
结尾
除了call
,还有两个类似的方法apply,bind
,这里就不做过多的解释了,相信小伙伴一定也能跟着这样的思路去手写出来。有什么问题就给我留言吧!