手写call、apply、bind

177 阅读1分钟

call

Function.prototype.call=function(context){
    //新建对象cxt保存需要this指向的对象,没有则指向window。严格模式会报错
    let cxt=context || window
    //创建一个属性,并赋值原型
    cxt.fn=this
    //获取传入的参数,call第一个为this指向,其他都是传入参数
    let args=Array.from(arguments).slice(1)
    //判断是否有参数传入
    let res=args?cxt.fn(...args):cxt.fn()
    //使用delete删除对象cxt.fn上的原型
    delete cxt.fn
    return res
}

apply

Function.prototype.apply=function(context){
    let cxt=context || window
    cxt.fn=this
    //获取传入的参数,apply第一个为this指向,其他参数都是第二个参数以数组形式传入
    let args=Array.from(arguments[1])
    let res=args?cxt.fn(...args):cxt.fn()
    delete cxt.fn
    return res
}

call与apply相差不大,只是传参方式不同。

bind

bind(thisArg[, arg1[, arg2[, ...]]])

thisArg:调用绑定函数时作为this参数传递给目标函数的值。
arg1, arg2, ...:当目标函数被调用时,预先添加到绑定函数的参数列表中的参数。

bind则需要注意几点:

  • bind传参方式与call相同
  • bind改变this指向后需调用在执行,call与apply则是直接执行
  • 如果使用new运算符构造绑定函数,则忽略该值。
  • 返回一个原函数的拷贝,并拥有指定的this值和初始参数。
Function.prototype.bind=function(context){
    if(typeof this !== 'function'){
        throw new TypeError('...')
    }
    
    
    var args=Array.from(arguments).slice(1),
        fToBind=this,
        fNOP=function(){},
        fBound=function(){
            return fToBind.call(
            // this instanceof fBound === true时,说明返回的fBound被当做new的构造函数调用
             this instanceof fBound?this:context||window,
             ...args.concat(Array.from(arguments))
            )
        }
    // 维护原型关系
    if(this.prototype){
        FNOP.prototype=this.prototype
    }
     //使fBound.prototype是fNOP的实例
     //返回的fBound若作为new的构造函数,new生成的新对象作为this传入fBound,新对象的__proto__就是fNOP的实例
    fBound.prototype=new FNOP()
    return FBound
}

给个三连吧,哐哐哐,别下次,别下次。