JS 手写call()方法

543 阅读1分钟

步骤

  • 首先明确call函数是定义在Function.prototype上的,为所有Function类型的对象所共享。现自定义Function.prototype.myCall.

传入参数:

  • 1、context表示谁来调用这个原函数
  • 2、...args用三点运算符直接将后面传入的参数解析成数组
  • 确定由谁来调用函数,命名为new_this;若没有传入要绑定的对象,默认绑定window对象
  • 把方法作为对象的属性绑定给new_this,但是注意,也许原有属性就有func这个属性,为了避免冲突,用symbol
  • 执行当前函数,并获取返回值
  • 删除我们绑定的Symbol(func)属性,以免污染new_this的属性
  • 返回第3步得到的返回值
// 传递参数从一个数组变成逐个传参,
// 不用...扩展运算符也可以用arguments代替
Function.prototype.myCall = function(context,...args){

    // 不需要判断类型,因为myCall定义在Function.prototype上
    
    if(typeof this !== 'function'){
       throw new TypeError(`${this} is not a function!`)
    }
    
    // 1、确定要绑定的对象,即最终谁来调用函数,命名为new_this;
    // 若没有传入要绑定的对象,默认绑定window对象
    
    const new_this = context || window
    
    // 2、把方法作为对象的属性绑定给new_this,但是要注意,也许原有属性就有func,
    // 为了避免冲突,这里用symbol
    
    const func = Symbol('func')
    
    // 由于这里func是Symbol变量不再是字符串,所以不能再用new_this,
    // func而是要用中括号获取属性
    
    new_this[func] = this
    
    // 3、执行当前函数,并获取返回值
    
    const res = new_this[func](...args)
    
    // 4、删除我们绑定的Symbol(func)属性,以免污染new_this的属性
    
    delete new_this[func]
    
    // 5、返回第三步得到的返回值
    
    return res
    
}

测试如下

var person = {
   name:'tom',
   age:12
}
function getInfo(a,b){
   var sum = a + b
   console.log('name:',this.name,'age:',this.age,'sum':sum)
}
getInfo.myCall(oerson,1,1) // name:tom,age.12.sum:2