用bind方法保持this上下文


近期自學JavaScript。學到bind方法這塊兒有些地方不太明確。自己就查了些資料,結合自己的理解寫了這篇文章以備后面回想用。

事實上應該還是搬磚為主吧。

什么是this對象

先來說說什么是this對象吧。每一個函數在調用的時候都會自己主動獲取兩個特殊變量:this和arguments對象。

this值詳細是指哪個對象是和該函數的運行環境相關的。假設是作為對象的方法,那么this就是對象實例本身;假設是一個全局函數,那么this就是window對象。用一句話來概括,this就是調用這種方法的對象。

保持this上下文

有時候。我們須要保持this的上下文,也就是在一個運行環境中想要訪問到還有一個運行環境的this值。在什么時候須要這么做呢?比方說將一個對象的方法賦值給了一個全局變量,然后在全局變量中調用這種方法,那么this值就不再是原來的對象而是window對象了,然而可能我們仍須要在全局環境中依照對象的方法來調用。又比方說一個方法中包括了閉包,閉包是無法訪問到其外部函數的this對象的,由於this對象是在調用方法的時候自己主動生成,內部函數在搜索這兩個變量的時候僅僅會搜索到其自身的活動對象。而不會沿着作用域鏈往外搜索,所以閉包訪問不到外部函數的this值。

假設要想訪問,就應該想辦法把this值傳遞下去。
通常能夠通過這種方式保持this上下文:在外部函數中將this緩存到一個變量中,通常變量名稱使用self, _this 或者 context。那么閉包就能夠通過這個可訪問的變量來獲取外部函數的this值,this上下文得以保持。比方以下的代碼:

var myObj = {

    specialFunction: function () {},
    getAsyncData: function (cb) {
        cb();
    },

    render: function () {
        var that = this;
        this.getAsyncData(function () {
            that.specialFunction();
        });
    }
};
myObj.render();

這里有一個對象myObj。它有一個render實例方法,在這種方法內部又調用了它的還有一個實例方法getAsyncData,而這種方法有一個新的函數作為參數,這個函數相當於是一個閉包。是不能獲取到外部函數中的this值的。為了在這個閉包中也能訪問實例方法,須要獲取到外部環境的this值,這里把this(this為調用render方法的對象。即實例對象myObj)緩存到了變量that中。

此外還可通過bind方法,這就是本文所要講述的重點。

bind方法

bind方法生成了一個新的函數,稱為綁定函數,傳入bind方法的第一個參數作為這個綁定函數的this對象,傳入bind的第二個參數連同后面調用綁定函數時傳入的參數依照先后順序(傳入bind的在前)構成綁定函數的參數。
如今我們把上面的樣例改動一下:

render: function () {
    this.getAsyncData(function () {

        this.specialFunction();

    }.bind(this));

}

.bind()創建了一個函數,當這個函數在被調用的時候。它的 this 關鍵詞會被設置成被傳入的值(這里指調用bind()時傳入的參數)
再看一個bind的使用樣例:

var foo = {
    x: 3
} 
var bar = function(){
    console.log(this.x);
} 
bar(); 
// undefined

var boundFunc = bar.bind(foo);

boundFunc(); 
// 3

將bar方法和foo對象綁定后,bar中的this對象被替換為了foo,並生成了一個新的函數boundFunc,因此在全局環境中調用boundFunc時。也能夠訪問到foo對象的屬性。
還能夠了解一下Function.prototype.bind()內部是什么樣的:

Function.prototype.bind = function (scope) {
    var fn = this;//this是調用bind方法的對象(別的方法對象)
    return function () {
        return fn.apply(scope);//把fn環境中的this替換為scope
    };
}

可看出,bind方法返回了一個新的函數。這種方法返回了原方法(調用bind的方法)通過apply改動作用域(傳入的參數scope)后的運行結果。假設調用這個新函數則會馬上運行fn.apply(scope)。並返回運行后的結果。

fn.bind()

與call、apply的差別

call、apply是改動函數的作用域,而且馬上運行。而bind是返回了一個新的函數,不是馬上運行,即call and apply call a function while bind creates a function。

bind在回調函數中經常使用到。

參考資料:
理解 JavaScript 中的 Function.prototype.bind
js中bind、call、apply函數的使用方法
https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Function/bind


免責聲明!

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



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