Function.prototype.bind分析
bind()方法會創建一個新的函數,成為綁定函數。當調用這個綁定函數時,綁定函數會以創建它時傳入的第一個參數作為this,傳入bind()方法的第二個以及以后的參數加上綁定函數運行時本身的參數按照順序作為原函數的參數來調取原函數。
實際使用中我們經常會碰到這樣的問題:
var name = "pig";function Person(name){ this.name = name; this.getName = function(){ setTimeout(function(){ console.log("Hello,my name is "+this.name); },100); }}var weiqi = new Person("衛旗");weiqi.getName(); //Hello,my name is pig這個時候輸出this.name是pig,原因是this的指向是在運行函數時確定的,而不是在定義函數時確定的,再因為setTimeout是在全局環境下只想,所以this就指向了window。
以前解決這個問題的辦法通常是緩存this,例如:
var name = "pig";function Person(name){ this.name = name; this.getName = function(){ //在這里緩存一個this var self = this; setTimeout(function(){ //在這里是有緩存this的self console.log("Hello,my name is "+self.name); },100); }}var weiqi = new Person("衛旗");weiqi.getName();//Hello,my name is 衛旗這樣就解決了這個問題,非常方便,因為它使得setTimeout函數中可以訪問Person的上下文。
現在有一個更好的解決辦法,可以使用bind()函數,上面的例子可以被更新為:
var name = "pig";function Person(name){ this.name = name; this.getName = function(){ setTimeout(function(){ console.log("Hello,my name is "+this.name); }.bind(this),100); //注意上面這一行,添加了bind(this) }}var weiqi = new Person("衛旗");weiqi.getName();//Hello,my name is 衛旗bind()最簡單的用法是創建一個函數,使得這個函數無論怎么樣調用都擁有同樣的this值。JavaScript新手經常犯的一個錯誤就是將一個方法從一個對象中拿出來,然后再調用,希望方法中的this是原來的對象(比如在回調函數中傳入這個方法)。如果不做特殊處理的話,一般會丟失原來的對象。從原來的函數和原來的對象創建一個綁定函數,則可以很漂亮的解決這個問題:
//定義全局變量xvar x = "window";//在module內部定義xvar module = { x:"module", getX:function(){ console.log(this.x); }}module.getX(); //返回module,因為在module內部調用getX()var getX = module.getX;getX();//返回window,因為這個getX()是在全局作用域中調用的//綁定getX()并將this值設為modulevar boundGetX = getX.bind(module);boundGetX();//返回module,綁定以后this值始終為module瀏覽器支持情況:
| Browser | Version support |
|---|---|
| Chrome | 7 |
| FireFox(Gecko) | 4.0(2) |
| Internet Explorer | 9 |
| Opera | 11.60 |
| Safari | 5.14 |
很不幸,Function.prototype.bind在IE8及以下版本中不被支持,所以如果沒有一個備選方案的話,可能會在運行時出現問題。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 () { return fToBind.apply(this instanceof fNOP && oThis ? this : oThis || window, aArgs.concat(Array.prototype.slice.call(arguments))); }; fNOP.prototype = this.prototype; fBound.prototype = new fNOP(); return fBound; };}語法
fun.bind(thisArg[, arg1[, arg2[, …]]])
參數
thisArg,當綁定函數被調用時,該參數會作為原函數運行時的this指向,當使用new操作符調用綁定函數時,該參數無效。
arg1, arg2, …,當綁定函數被調用時,這些參數加上綁定函數本身的參數會按照順序作為原函數運行時的參數。
描述
bind()函數會創建一個新的函數(一個綁定的函數)有同樣的函數體(在ECMAScript 5 規范內置Call屬性),當該函數(綁定函數的原函數)被調用時this值綁定到bind()的第一個參數,該參數不能被重寫。綁定函數被調用時,bind()也接受預設的參數提供給原函數。一個綁定函數也能使用new操作符創建對象:這種行為就像把原函數當成構造器。提供的this值被忽略,同事調用的參數被提供給模擬函數。
感謝閱讀,希望能幫助到大家,謝謝大家對本站的支持!
新聞熱點
疑難解答