我试图编写一个可以在同一页面内的多个元素上初始化的新插件,每次都有不同的选项,例如:
$('#id').plugin({ option:true });
$('#id2').plugin({ option:false });
我使用了jqueryboilerplate.com(https://github.com/jquery-boilerplate/jquery-boilerplate)的样板文件。我理解(至少我认为我这样做!)问题是在匿名函数的范围内(这里,在setTimeout内)'这个'指的是窗口。所以在下面,输出是第一次记录,而不是第二次:
// 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设置为' value'。 Console.log结果是:
value
Uncaught TypeError: Cannot read property 'propertyName' of undefined
例如,如果我设置了window.prop = this.settings.propertyName和console.log window.prop,那么可行,但问题是可能有许多实例同时运行。
我已经阅读了很多与此主题相关的问题,但似乎没有人真正解决这个问题。如果有人能够在使用样板文件的jQuery插件的上下文中给出一个明确的示例,我将不胜感激,或类似的东西。请原谅我的noobness,谢谢!!
答案 0 :(得分:1)
在this
:
$.extend(Plugin.prototype, {
init: function () {
var _this = this;
console.log(this.settings.propertyName);
setTimeout(function(){
console.log(_this.settings.propertyName);
}, 1000);
}
});
答案 1 :(得分: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);
}
});
答案 2 :(得分: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);
}
});