看看真正的call方法,手撕代码实现

我们现在先来看个小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是一个数组,但是使用...展开符进行操作。
经验分享 程序员 微信小程序 职场和发展