面试官:请实现一个bind函数

292 阅读1分钟
  1. 首先我们要了解bind函数的用法,通过用法进行模拟
  2. bind用法:fn.bind(obj,x,y,...) obj为绑定this指向对象,x,y为绑定参数。
  3. 了解了上述用法我们开始说干就干

第一步 我们先把obj和参数绑定上去

Function.prototype.myBind = function(){
    const targetFn = this; // 目标函数
    const [targetObj,...targetArgs] = [...arguments]; // 解构对象及绑定时参数
    
    if(typeof targetFn !== 'function')  {
        throw `${this} must be a function`
    }
     
    return function(){
        targetFn.apply(targetObj,targetArgs);
    }
}

第二步 我们发现上述函数生成新的函数后不能传参了,因此我们进行下改造

Function.prototype.myBind = function(){
    const targetFn = this; // 目标函数
    const [targetObj,...targetArgs] = [...arguments]; // 解构对象及绑定时参数
    
    if(typeof targetFn !== 'function')  {
        throw `${this} must be a function`
    }
    
    return function(...args){
        targetFn.apply(targetObj,[...targetArgs, ...args]);
    }
}

第三步 我们绑定后的函数必须支持new 然而此时我们怎么new也new不正确就因为我们永远都是作用于目标对象 因此我们要进行判断是否使用new

Function.prototype.myBind = function(){
    const targetFn = this; // 目标函数
    const [targetObj,...targetArgs] = [...arguments]; // 解构对象及绑定时参数
    
    if(typeof targetFn !== 'function')  {
        throw `${this} must be a function`
    }
    
   const newFn = function(...args){
        const isNewFlag = this instanceof newFn // 如果进行了new 那么new出来的对象也就是this指向一定为newFn的实例 此处会为true;
        targetFn.apply(isNewFlag ? this : targetObj,[...targetArgs, ...args]);
        // 此处做判断,如果为new操作符的话 所有绑定应为此刻new的对象上
    }
    
    return newFn 
}

第四步 new出来的对象其__proto__指向了新bind的函数 然而当前函数的prototype并没有指向原targetFn的prototype 因此我们需要设定一下 并注意不能直接引用否则再更改新bind出来的函数的prototype时会造成targetFn原型的修改

Function.prototype.myBind = function(){
    const targetFn = this; // 目标函数
    const [targetObj,...targetArgs] = [...arguments]; // 解构对象及绑定时参数
    
    if(typeof targetFn !== 'function')  {
        throw `${this} must be a function`
    }
    
   const newFn = function(...args){
        const isNewFlag = this instanceof newFn // 如果进行了new 那么new出来的对象也就是this指向一定为newFn的实例 此处会为true;
        targetFn.apply(isNewFlag ? this : targetObj,[...targetArgs, ...args]);
        // 此处做判断,如果为new操作符的话 所有绑定应为此刻new的对象上
    }
    
    const temporarilyFn = function(){};
    temporarilyFn.prototype = targetFn.prototype;
    newFn.proptotype = new temporarilyFn();
    
    return newFn 
}

以上便是我们bind函数的自我实现,其中与浏览器相比有一点不同的就是浏览器实现的bind函数是没有prototype属性的,但是当其使用new操作符时却仍然能够将其__proto__ 引用为targetFn的原型prototype上 很是神奇 有知道如何实现的大佬可以给予一下思路~