原生Javascript實現Bind

野生鬆發表於2020-10-29

Bind:

bind() 方法會建立一個新函式。當這個新函式被呼叫時,bind() 的第一個引數將作為它執行時的 this,之後的一序列引數將會在傳遞的實參前傳入作為它的引數。(來自於 MDN )

接下來例子結合原始碼來分析:

//測試
var value = 2;

var foo = {
    value: 1
};

function bar(name, age) {
    this.habit = 'shopping';
    console.log(this.value);
    console.log(name);
    console.log(age);
}

bar.prototype.friend = 'kevin';

var bindFoo = bar.bind(foo, 'daisy');

var obj = new bindFoo('18');
// undefined
// daisy
// 18
console.log(obj.habit);
console.log(obj.friend);
// shopping
// kevin

Function.prototype.myBind = function(context, ...args){
  // 獲取自身的this,也就是 bar
  let self = this;
  let targetFuc =  function(){
    // 獲取繫結的函式的傳參,也就是 '18'
    let targetArg = Array.prototype.call.slice(arguments)
    // 以例子來看就是將bar的this指向context,也就是fo
    // 正常來說是 self.apply(context,args.concat(targetArg)) 就行了
    // 但是因為bind的返回可以用new繫結,new會改變this指向:
    // 如果bind繫結後的函式被new了,那麼this指向會發生改變,指向當前函式的例項。也就是targetFuc
    // this instanceof targetFuc 判斷返回的函式是否被new繫結在了例項上
    // 因為bind()除了this還接收其他引數,bind()返回的函式也接收引數,這兩部分的引數都要傳給返回的函式
    // args.concat(targetArg) 就相當於 ['daisy'].concat(['18])
    return self.apply(this instanceof targetFuc ? this: context,args.concat(targetArg))
  }
   // 修改返回函式的 prototype 為繫結函式的 prototype,例項就可以繼承繫結函式的原型中的值,也就是friend和habit
   targetFuc.prototype = Object.create(self.prototype);
   return targetFuc
}

解釋就不多說了,看備註寫的很清楚

相關文章