學到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();
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
這裏有一個對象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));
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
.bind()創建了一個函數,當這個函數在被調用的時候,它的 this 關鍵詞會被設置成被傳入的值(這裏指調用bind()時傳入的參數)
再看一個bind的使用例子:
var foo = {
x: 3
}
var bar = function(){
console.log(this.x);
}
bar();
// undefined
var boundFunc = bar.bind(foo);
boundFunc();
// 3
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
將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
};
}
- 1
- 2
- 3
- 4
- 5
- 6
- 1
- 2
- 3
- 4
- 5
- 6
可看出,bind方法返回了一個新的函數,這個方法返回了原方法(調用bind的方法)通過apply修改作用域(傳入的參數scope)後的執行結果。如果調用這個新函數則會立即執行fn.apply(scope),並返回執行後的結果。
fn.bind()
- 1
- 1
與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