bind Polyfill詳細解javascript bind

3321 ワード

前端面接でよく出会う面接の質問です.手書きで書くbindの方法です.
この文章はECMAScriptの中のbind Polyfillについてbind方法を詳しく説明します.詳しくはMDNを参照してください.
まず、bind() call() apply()はjavascriptのthisと密接に関係しています.彼らは共通の役割を持っています.つまり、thisオブジェクトに対して明示的に結合しています.bind()は何をするものですか?bind()方法会==新しい関数を作成します.bind()が呼び出されたとき、新しい関数のthisbind()の最初のパラメータに指定されます.残りのパラメータは新しい関数のパラメータとして呼び出されるときに使用されます.
const obj = {
    name: 'lily',
    getName: function() {
        return this.name
    }
}

let fn = obj.getName

console.log(fn())  // undefined      fn this   [object Window]

let fn2 = fn.bind(obj, 1, 2, 3)

console.log(fn2()) // 'lily'   bind() this     obj 
bind()文法
fn.bind(obj, arg1, arg2 )
this指向を変更する以外に、bind()は他の用途があります.
プリセットパラメータ
ここにもう一つのポイントがあります.bindの最初のパラメータがnullまたはundefinedの場合、呼び出しの関数thisは、非厳密なモードでwindowを指し、厳格なモードではTypeError: this is undefinedをエラーとします.
function preset() {
    return Array.prototype.slice.call(arguments)
}

let list1 = list(1, 2, 3) // [1, 2, 3]

let presetList = list.bind(null, 666)

let list2 = presetList() // [666]
let list3 = presetList(777, 888, 999) // [666, 777, 888, 999]
bind() Polifill
このような書き方は、new funcA.bind(thisArg, args)オペレータがnewポインタを変更してもよく、優先度が一番高いので、コンストラクションthisでは使用できない.
if (!Function.prototype.bind) (function() { //    bind
  let slice = Array.prototype.slice // slice      
  
  Function.prototype.bind = function() {
    let thatFunc = this,  //   bind   
        thatArg = arguments[0],  //     
        args = slice.call(arguments, 1) //     
    
    if (typeof thatFunc !== 'function') {  //   bind()      ,  bind       
      throw new TypeError('only Function can be bound')
    }
    
    return function(){
      let funcArgs = args.concat(slice.call(arguments))  //     ,  bind        ,                
      return thatFunc.apply(thatArg, funcArgs);
    }
  }
})()
下の書き方はnew funcA.bind(thisArg, args)に使えます.
if (!Function.prototype.bind) (function(){ //    bind
  var ArrayPrototypeSlice = Array.prototype.slice;  // slice      
  
  Function.prototype.bind = function(otherThis) {
  
    if (typeof this !== 'function') { //   bind()      ,  bind       
      throw new TypeError('only Function can be bound');
    }

    let baseArgs= ArrayPrototypeSlice .call(arguments, 1),  //     
        baseArgsLength = baseArgs.length, //       
        fToBind = this, //   bind   
        fNOP = function() {},  //          
        fBound = function() {  // 
          baseArgs.length = baseArgsLength; // reset to default base arguments
          baseArgs.push.apply(baseArgs, arguments); //     
          return fToBind.apply(
            //    new      ,         this  bind this
            fNOP.prototype.isPrototypeOf(this) ? this : otherThis, baseArgs
          );
        };

    if (this.prototype) {
      fNOP.prototype = this.prototype; 
    }
    fBound.prototype = new fNOP(); //    new                     

    return fBound;
  };
})();