js手写call、apply、bind方法

call

逐步实现,最后得出最终版
先熟悉一下call的功能及使用

 需求:想让函数打印出user 的name,即想让函数中的this指向user(修改this指向)
   const user = {
        name: "zhangsan"
    }
    function sayYourName(title) {
        console.log(title,this.name)
    }
    // 使用js内置的api call方法
    sayYourName.call(user,'hello')    //函数立即调用,并打印
    // 或者利用对象属性 直接调用
     const user1 = {
        name: "zhangsan",
        sayYourName:function(title) {
            console.log(title,this.name)
        }
    }
    user1.sayYourName('hello')
    

根据上面的思路,我们自己一个封装一个call方法

 function myCall(fn,context,...args){ // ES6剩余参数
        context.fn = fn
        const res = context.fn(...args)//扩展运算符
        delete context.fn
        return res
    }
    myCall(sayYourName,user,'hello')

// 优化:如果context 里面本身就有一个fn的属性,给它重新赋值,然乎又删掉,明显不合理,所以要保证利用的属性名的唯一性
function myCall(fn,context,...args){ // ES6剩余参数
        const fnName = Symbol()
        context[fnName]=fn
        const res = context[fnName ](...args)//扩展运算符
        delete context[fnName ]
        return res
    }
    myCall(sayYourName,user,'hello')

总结:

  1. 先把函数赋值给目标的的属性
  2. 利用目标对象对象 调用函数
  3. 删除目标对象的属性
  4. 将函数结果返回
    但是仍然封装好的myCall方法并不能采用 函数.myCall的形式调用

js内置的call方法 采用 函数.call的形式调用,但是函数本身并没有call方法,js就会向函数的原型链上查找,其实call方法就是存在与 Function.prototype上的一个属性。

所以我们进行下一步:把我们的myCall方法也挂载到函数原型上

Function.prototype.myCall = function(fn,context,...args){
		const fnName = Symbol()
        context[fnName]=fn
        const res = context[fnName ](...args)//扩展运算符
        delete context[fnName ]
        return res
}
//使用:
sayYourName.myCall(sayYourName,user,'hello')
  1. 我们不难发现 myCall方法中的this是调用它的对象,即sayYourName,所以实参中的sayYourName可以用this代替
  2. 同时我们的函数形参也要替换成this,如下:call最终版
Function.prototype.myCall = function(context,...args){
   	const fnName = Symbol()
       context[fnName]=this
       const res = context[fnName ](...args)//扩展运算符
       delete context[fnName ]
       return res
}
//使用:
sayYourName.myCall(user,'hello')

apply

基本与myCall实现一样,只是apply的传参形式为数组

Function.prototype.myApply = function(context,args){  //只需要把...args 去掉...,直接传递数组过去
   	const fnName = Symbol()
       context[fnName]=this
       const res = context[fnName ](...args)//扩展运算符
       delete context[fnName ]
       return res
}
//使用:
sayYourName.myApply(user,['hello'])

bind

  1. bind 方法将创建并返回一个新的函数,新函数称为绑定函数,并且绑定函数包裹着原始函数
  2. 在执行时,会显示的将原始函数内部的this指向context
  3. 除context外,所有剩余参数将全部传递给原始函数function
  4. 执行绑定函数时,如果传递了参数,这些参数将全部传递给原始函数 function
  5. 如果使用了new运算符调用生成的绑定函数,则忽略context

你可能感兴趣的:(面试,javascript,前端)