2015-04-22 55 views
0

我試圖寫一個新的插件,可以對多個元素在同一頁面內被初始化,使用不同的選項,每次,EX插件:jQuery的多個實例使用「this」中的setTimeout

$('#id').plugin({ option:true }); 
$('#id2').plugin({ option:false }); 

我使用jqueryboilerplate.com的樣板(https://github.com/jquery-boilerplate/jquery-boilerplate)。我理解(至少我認爲我是這麼做的),問題是在匿名函數的範圍內(這裏,在setTimeout內),'this'指向窗口。所以在下面,輸出記錄的第一次,但不是第二:

// Avoid Plugin.prototype conflicts 
$.extend(Plugin.prototype, { 
    init: function() { 
     console.log(this.settings.propertyName); 
     setTimeout(function(){ 
      console.log(this.settings.propertyName); 
     }, 1000); 
    } 
}); 

別處this.settings.propertyName設置爲「價值」。 CONSOLE.LOG結果是:

value 
Uncaught TypeError: Cannot read property 'propertyName' of undefined 

舉例來說,如果我設置window.prop = this.settings.propertyName和執行console.log window.prop代替,這樣的作品,但問題是,有可能運行許多實例與此同時。

我已閱讀了很多與此主題相關的問題,但似乎沒有一個能夠真正解決這種特殊情況。如果有人能夠給我一個清楚的例子,說明如何在使用樣板的jQuery插件或類似的東西的背景下做到這一點,我將不勝感激。請原諒我的noobness,謝謝!

回答

1

捕捉上this封閉:

$.extend(Plugin.prototype, { 
    init: function() { 
     var _this = this; 
     console.log(this.settings.propertyName); 
     setTimeout(function(){ 
      console.log(_this.settings.propertyName); 
     }, 1000); 
    } 
}); 
1

setTimeout作爲window.setTimeout執行,所以setTimeout處理程序的上下文被設定爲window對象。如果你想改變它的上下文,你可以使用bind()

setTimeout(function() { 
    // this.xyz 
    // use this here 
}.bind(this), 1000); 

bind將setTimeout以外的上下文綁定到它內部的上下文。

參考https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/bind

您也可以緩存的背景下,並用它裏面setTimeout

// Avoid Plugin.prototype conflicts 
$.extend(Plugin.prototype, { 
    init: function() { 
     var self = this; // Cache context 

     setTimeout(function() { 
      console.log(self.settings.propertyName); // Use cached context instead of `this` 
     }, 1000); 
    } 
}); 
1

發生這種情況的原因是超時中的this引用了窗口對象。它可以很容易固定通過保持一個參考值的功能外這樣的:

// Avoid Plugin.prototype conflicts 
$.extend(Plugin.prototype, { 
    init: function() { 
     console.log(this.settings.propertyName); 
     var self = this; 
     setTimeout(function(){ 
      console.log(self.settings.propertyName); //Use your reference here. 
     }, 1000); 
    } 
}); 

如果由於某種原因,你不喜歡具有參考的變量,你可以隨時使用Function.prototype.bind。使用前務必檢查compatibility.bind所做的只是在修改this值和參數時返回一個新函數。你可以這樣使用它:

// Avoid Plugin.prototype conflicts 
$.extend(Plugin.prototype, { 
    init: function() { 
     console.log(this.settings.propertyName); 
     setTimeout(function(){ 
      console.log(this.settings.propertyName); 
     }.bind(this), 1000); 
    } 
});