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,这里就不做过多的解释了,相信小伙伴一定也能跟着这样的思路去手写出来。有什么问题就给我留言吧!