jQuery多实例插件使用"这个"在setTimeout中

时间:2015-04-22 17:58:20

标签: javascript jquery jquery-plugins

我试图编写一个可以在同一页面内的多个元素上初始化的新插件,每次都有不同的选项,例如:

$('#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,谢谢!!

3 个答案:

答案 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);
    }
});