手写我们看一段手写call的应用:
var p1={
name:'jack',
getName(){
return this.name;
}
}
var p2={
name:'rose',
}
Function.prototype.mycall=function (context,...args){
const newThis = context || window;
<!-- console.log(context);-->
<!-- console.log(this);-->
newThis.fn =this;
const result =newThis.fn(...args);
delete newThis.fn;
return result;
}
console.log(p1.getName.mycall(p2));
console.log(p2);
<!-- 原型里的this指向,构造函数实例,也就是getName(),-->
<!--这里的过程,先用一个变量保存穿进来的对象,然后在这个对象的属性上保存getName方法,这样执行这个方法的时候,getName函数的this就指向p2-->
一步一步来,mycall是一个函数,参数是传入的对象+参数。传入的对象可能没有,这个时候内部的上下文是window。为什么用上下文定义这个变量呢,可以想想,因为这个函数是在传入的对象的上下文中执行的。现在可能不懂,之后会看懂的。
第一步,用一个变量newThis保存传入的参数对象,根据定义这个参数没有的时候是window。
第二步,newThis.fn=this,先看这个this,我在上面打印出来了是getName()函数,为什么呢,因为构造函数的原型的this指向构造函数的实例,左边的呢,为什么需要用newthis.fn呢,第一步知道newthis是传入的对象,在对象的身上加一个属性保存getName函数
第三步,const result =newThis.fn(...args);调用getName函数,这个函数被p2调用,所以getName()的this指向p2,如果这个函数有返回的话,就把它保存在result变量里,之后返回。这里可以知道为什么这个变量定义成context了,因为函数运行在context里,这里就是传入的参数,可以这么说,虽然不太正确,可能这里用广义的定义上下文了,因为没有上下文是一个对象的。
第四步,为了避免变量污染,所以必须加这一步。
第五步,返回result。