1. 程式人生 > >理解bind方法使用與實現

理解bind方法使用與實現

reset eof 另一個 構建 問題 tostring 瀏覽器 property this指向

方法描述

bind()方法創建一個新函數,當被調用時,將其this關鍵字設置為提供的值。

語法說明

fn.bind(thisArg,arg1,arg2,..)

參數說明

thisArg:當綁定函數被調用時,該參數會作為原函數運行時的this指向。當使用new操作符調用綁定函數時,該參數無效。
arg1,arg2,…:當綁定函數被調用時,這些參數將傳遞給被綁定的方法。

應用場景

1、創建綁定方法

this.x = 9; 
var module = {
  x: 81,
  getX: function() { return this.x; }
};

module.getX(); // 返回 81

var retrieveX = module.getX;
retrieveX(); // 返回 9, 在這種情況下,"this"指向全局作用域

// 創建一個新函數,將"this"綁定到module對象
// 新手可能會被全局的x變量和module裏的屬性x所迷惑
var boundGetX = retrieveX.bind(module);
boundGetX(); // 返回 81

2、偏函數
bind()的另一個簡單用法就是使一個函數擁有預設的初始參數。這些參數會作為bind()的第二個參數跟在this後面,之後它們會插入到目標函數的參數列表的開始位置,傳遞給綁定函數的參數會跟在它們後面。

function list() {
  return Array.prototype.slice.call(arguments);
}

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

// Create a function with a preset leading argument
var leadingThirtysevenList = list.bind(undefined, 37);

var list2 = leadingThirtysevenList(); // [37]
var list3 = leadingThirtysevenList(1, 2, 3); // [37, 1, 2, 3]

3、配合setTimeout
在默認情況下,使用window.setTimeout()時,this關鍵字會指向window(或全局)對象。當使用類的方法時,需要this引用類的實例,需要顯式地把this綁定到回調函數以便繼續使用實例。

4、作為構造函數使用的綁定函數
綁定函數適用於用new操作符去構造一個由目標函數創建的新的實例。當一個綁定函數是用來構建一個值的,原來提供的 this 就會被忽略。然而, 原先提供的那些參數仍然會被前置到構造函數調用的前面。

function Point(x, y) {
  this.x = x;
  this.y = y;
}

Point.prototype.toString = function() { 
  return this.x + ',' + this.y; 
};

var p = new Point(1, 2);
p.toString(); // '1,2'

var emptyObj = {};
var YAxisPoint = Point.bind(emptyObj, 0/*x*/);
// 以下這行代碼在 polyfill 不支持,
// 在原生的bind方法運行沒問題:
//(譯註:polyfill的bind方法如果加上把bind的第一個參數,即新綁定的this執行Object()來包裝為對象,Object(null)則是{},那麽也可以支持)
var YAxisPoint = Point.bind(null, 0/*x*/);

var axisPoint = new YAxisPoint(5);
axisPoint.toString(); // '0,5'

axisPoint instanceof Point; // true
axisPoint instanceof YAxisPoint; // true
new Point(17, 42) instanceof YAxisPoint; // true

Polyfill

bind()函數在 ECMA-262 第五版才被加入;它可能無法在所有瀏覽器上運行。你可以部份地在腳本開頭加入以下代碼,就能使它運作,讓不支持的瀏覽器也能使用 bind() 功能。

if (!Function.prototype.bind) {
  Function.prototype.bind = function(oThis) {
    if (typeof this !== 'function') {
      // closest thing possible to the ECMAScript 5
      // internal IsCallable function
      throw new TypeError('Function.prototype.bind - what is trying to be bound is not callable');
    }

    var aArgs   = Array.prototype.slice.call(arguments, 1),
        fToBind = this,
        fNOP    = function() {},
        fBound  = function() {
          // this instanceof fNOP === true時,說明返回的fBound被當做new的構造函數調用
          return fToBind.apply(this instanceof fNOP
                 ? this
                 : oThis,
                 // 獲取調用時(fBound)的傳參.bind 返回的函數入參往往是這麽傳遞的
                 aArgs.concat(Array.prototype.slice.call(arguments)));
        };

    // 維護原型關系
    if (this.prototype) {
      // Function.prototype doesn't have a prototype property
      fNOP.prototype = this.prototype; 
    }
    // 下行的代碼使fBound.prototype是fNOP的實例,因此
    // 返回的fBound若作為new的構造函數,new生成的新對象作為this傳入fBound,新對象的__proto__就是fNOP的實例
    fBound.prototype = new fNOP();

    return fBound;
  };
}

原文連接

https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Function/bind

理解bind方法使用與實現