淺析 JavaScript 中的 Function.prototype.bind() 方法


Function.prototype.bind()方法

bind() 方法的主要作用就是將函數綁定至某個對象,bind() 方法會創建一個函數,函數體內this對象的值會被綁定到傳入bind() 函數的值。

例如,在 f() 函數上調用 bind() 方法並傳入參數 obj ,即 f.bind(obj) ,這將返回一個新函數, 新函數會把原始的函數 f() 當做 obj 的方法來調用,就像 obj.f() 似的,當然這時 f() 函數中的 this 對象指向的是 obj

簡單使用情形一

var o={
    f: function () {
        var self=this;
        var fff=function() {
            console.log(self.value);  //此時 this 指向的是全局作用域 global/window,因此需要使用 self 指向對象o
        };
        fff();
    },
    value: "Hello World!"
};
o.f(); // Hello World! 

上例是我們常用了 保持 this 上下文的方法,把 this 賦值給了中間變量 self,這樣在內部嵌套的函數中能夠使用 self 訪問到對象o,否則仍使用 this.value,內部嵌套函數的this此時指向的是全局作用域,最后的輸出將會是 undefined,代碼如下:

var o={
    f: function () {
        var self=this;
        var fff=function() {
            console.log(this.value); 
        };
        fff();
    },
    value: "Hello World!"
};
o.f(); // undefined

但是,如果我們使用 bind()函數,將fff函數的綁定在對象o中,即將fff()函數內部的 this 對象綁定為對象 o,那么可以遇見此時 this.value 是存在的。代碼如下:

var o={
    f: function () {
        var self=this;
        var fff=function() {
            console.log(this.value); // bind(this) 中 this 指向的是o,這里也可直接寫成 bind(o)
        }.bind(this);
        fff();
    },
    value: "Hello World!"
};
o.f(); // Hello World!

更普遍的使用情形

再看一個例子:

function f(y,z){
    return this.x+y+z;
}
var m=f.bind({x:1},2); 
console.log(m(3));  // 6

最后將輸出 6

這是因為 bind()方法會把傳入它的第一個實參綁定給f函數體內的 this,從第二個實參起,將依此傳遞給原始函數,因此 {x:1}傳遞給this ,2傳遞給形參ym(3) 調用時的3 傳遞給形參z

其實這個例子 f() 函數能夠處理部分參數,分步計算 ( bind() 時處理了參數x,和參數y,調用 m(3)時處理了參數z )的過程其實是一個典型的Curry過程(Currying)。

bind()背后的簡單原理

那么bind函數背后做了什么呢? 我們可以用以下代碼來模擬:

Function.prototype.testBind = function (scope) {
    var fn = this;                                // this 指向的是調用testBind方法的一個函數
    return function () {
        return fn.apply(scope, arguments);
    }
};

下面是測試的例子:

var foo = {x: "Foo "};
var bar = function (str) {
    console.log(this.x+(arguments.length===0?'':str));
};

bar();                                   // undefined

var testBindBar = bar.testBind(foo);     // 綁定 foo
testBindBar("Bar!");                     // Foo Bar!

當調用 testBind() 后,我們創建了一個新的函數,通過調用 applythis 設置成 foo, OK,現在應該比較清晰了,但實際 bind() 的實現遠比上面的復雜,如上面提到的 curry化過程等,上面只是主要原理便於學習理解 bind() 函數。

參考資料:
Javascript權威指南


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM