2015-04-22 52 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); 
    } 
});