bind(),apply(),call()理解

Function.prototype.call()

// call函數的簽名
fun.call(thisArg, arg1, arg2, ...)
複製代碼

call函數能夠這樣理解數組

  • 容許爲不一樣的對象分配和調用屬於一個對象的函數/方法
  • 提供新的 this 值給當前調用的函數/方法。

參數:app

  • thisArg: 在 fun 函數運行時指定的 this 值。
  • arg1..:指定的參數列表。

call函數把某個方法的this改爲了第一個參數。給該函數傳入多個參數,並執行當前函數。函數

call函數有這麼幾個要點,須要理解:ui

  • this能夠傳null,能夠傳空,這時候this指向window
  • 函數是能夠有返回值的!有返回值返回返回值,沒有返回值返回undefined
/* 把函數當成對象,而後刪除對應的屬性值 */
    Function.prototype.call2 = function (context) {
    	// 判斷當前的this對象是否爲null,爲空指向window
      var context = context || window;
    	// 首先要獲取調用call的函數,用this能夠獲取
      context.fn = this;
    
      var args = [];
    	// 獲取call的參數
      for(var i = 1, len = arguments.length; i < len; i++) {
          args.push('arguments[' + i + ']');
      }
    	// eval執行該函數
      var result = eval('context.fn(' + args +')');
    	// 刪掉調用對象的這個屬性
      delete context.fn
      return result;
    }
複製代碼

Function.prototype.apply()

// apply的函數簽名
func.apply(thisArg, [argsArray])
複製代碼

apply函數和call函數實現的是相同的功能this

  • 容許爲不一樣的對象分配和調用屬於一個對象的函數/方法
  • 提供新的 this 值給當前調用的函數/方法。

apply函數的參數:spa

  • thisArg: 在 fun 函數運行時指定的 this 值。
  • argsArray:指定的參數數組。

實現:prototype

Function.prototype.apply = function (context, arr) {
       // 判斷當前的this對象是否爲null,爲空指向window
      var context = context || window;
    	// 首先要獲取調用call的函數,用this能夠獲取
      context.fn = this;
    
      var result;
      if (!arr) {
          result = context.fn();
      }
      else {
          var args = [];
          for (var i = 0, len = arr.length; i < len; i++) {
              args.push('arr[' + i + ']');
          }
          result = eval('context.fn(' + args + ')')
      }
    
      delete context.fn
      return result;
    }
複製代碼

Function.prototype.bind()

// bind函數的函數簽名
function.bind(thisArg[, arg1[, arg2[, ...]]])
複製代碼

bind()方法建立一個新的函數,在bind()被調用時,這個新函數的this被bind的第一個參數指定,其他的參數將做爲新函數的參數供調用時使用。code

參數:對象

  • thisArg 在 fun 函數運行時指定的 this 值。
  • arg1..:指定的參數列表。

bind() 函數生成的新函數,不能本身執行,須要手動執行一下。可是這個新函數的this永遠都是bind的第一個參數。繼承

由於 bind 還有一個特色,就是

一個綁定函數也能使用new操做符建立對象:這種行爲就像把原函數當成構造器。提供的 this 值被忽略,同時調用時的參數被提供給模擬函數。

也就是說當 bind 返回的函數做爲構造函數的時候,bind 時指定的 this 值會失效,但傳入的參數依然生效

實現

Function.prototype.bind2 = function (context) {
    	// 調用bind的是不是函數作一個判斷
      if (typeof this !== "function") {
        throw new Error("Function.prototype.bind - what is trying to be bound is not callable");
      }
    	// 把調用者和要傳給函數的參數保存一下。
      var self = this;
    	// 獲取bind2函數從第二個參數到最後一個參數
      var args = Array.prototype.slice.call(arguments, 1);
    	// 建立一個空函數來中轉
      var fNOP = function () {};
    
      var fBound = function () {
          var bindArgs = Array.prototype.slice.call(arguments);
    			// 看成爲構造函數時,this 指向實例,此時結果爲 true,將綁定函數的 this 指向該實例,可讓實例得到來自綁定函數的值
          // 以上面的是 demo 爲例,若是改爲 `this instanceof fBound ? null : context`,實例只是一個空對象,將 null 改爲 this ,實例會具備 habit 屬性
          // 看成爲普通函數時,this 指向 window,此時結果爲 false,將綁定函數的 this 指向 context
          return self.apply(this instanceof fNOP ? this : context, args.concat(bindArgs));
      }
    	// 修改返回函數的 prototype 爲綁定函數的 prototype,實例就能夠繼承綁定函數的原型中的值
      fNOP.prototype = this.prototype;
      fBound.prototype = new fNOP();
      return fBound;
    }
複製代碼
相關文章
相關標籤/搜索