我们现在先来看个小demo
function fn(){
let a = this.a
console.log(a)
}
let obj = {
a: 1,
objFn: fn
}
let obj2 = {
a: 2,
// objFn: fn
}
obj.objFn()
fn.call(obj2) //
打印结果:
我们的call方法其实就是改变函数的上下文,或者说call方法就是改变this指向的。注意,我们在obj2中没有引用fn方法,但是也是可以使用的。说明,call方法就只是提供上下文,并且调用函数。
那我们来手写实现一下代码:
// 1没有传递给函数的上下文,那就是默认为window
// 2防止以Function.protiType.call()的形式直接调用
Function.prototype.call = function(context = window,...args){
// 防止以Function.protiType.call()的形式直接调用
if(this === Function.prototype){
return undefined
}
// 为什么需要使用symbol?
// 因为在call方法提供的环境中没有fn()方法的引用
// 如上文,在obj2中没有fn函数的引用
// 所以我们使用symbol创建一个唯一的函数名,当做函数的临时引用
// 我们在使用Symbol的时候需要时Symbol(),而不是new来调用构造函数
// 两个symbol是不相同的
const fnSymbol = Symbol()
console.log(fnSymbol)
context[fnSymbol] = this
// 调用并销毁
const reslut = context[fnSymbol](...args)
delete context[fnSymbol]
// 返回的是指向函数的返回值
return reslut
}
小知识点:上文中用...args接受后面的所有函数,变相的以一个数组来接收函数,args是一个数组,但是使用...展开符进行操作。