jQuery 在 setTimeout 中使用 "this" 的多实例插件

jQuery multiple instance plugin using "this" in setTimeout

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

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

我正在使用来自 jqueryboilerplate.com (https://github.com/jquery-boilerplate/jquery-boilerplate) 的样板文件。我理解(至少我认为我理解!)问题是在匿名函数的范围内(这里,在 setTimeout 内)'this' 指的是 window。所以在下面,第一次记录输出,而不是第二次:

// 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,那是可行的,但问题是可能有很多实例 运行 同时.

我已经阅读了很多与此主题相关的问题,但 none 似乎确实解决了这种特殊情况。如果有人能给我一个清楚的例子,说明如何在 jQuery 插件的上下文中使用样板或类似的东西来做到这一点,我将不胜感激。请原谅我的笨拙,谢谢!!

捕获 this 上的闭包:

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

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

这是因为超时中的this引用了window对象。通过在函数外部保留一个引用可以很容易地修复它:

// 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. Be sure to check the 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);
    }
});