直接上代码
Function.prototype.myCall = function(context, ...args) {
context = typeof context==='object'?context: window
const key = Symbol('key')
// 下面的这个 this 是 个方法,谁调用该方法就是谁
context[key] = this
// 当调用这个方法并传参数时,**this的指向已经变成了context**
const res = context[key](...args)
delete context[key]
return res
}
举个栗子
function bar() {
this.name = 'aaa'
// return this.name
}
let obj= {
k:1,
}
bar.myCall(obj)
解释
call源码中最难以理解的就是 第三行和第四行代码了。我们结合 例子来解读。例子中有一个方法 bar 和一个 对象 obj,我们的目标是将 bar 中的 name 赋给 obj,使得 obj ={k:1, name:'aaa'}
.
对于 context[key] = this,其实就是在 obj中加入了一个key,该key为 一个 不会重复的Symbol(防止覆盖obj原有属性),value就是 this,而this 就是 调用 call的那个方法。 这个时候
obj = { k:1, Symbol(key): bar}
一旦执行 context\[key](...args)
这行代码时,原本 在 bar 的属性name 在obj同样也会生成一份,因为函数的调用是通过 context + . 的形式,涉及到this指向问题。obj. 的方式调用,this就指向 obj。
因此这是可以得到
obj= { k:1, Symbol(key): bar, name:'aaa'}
下一行代码就将 Symbol删除了。
总结
虽然只是一个小小的call,但是里面蕴含的确实 this 指向最基础的知识点。