1

我对 JavaScript 比较陌生,无法理解为什么会发生此错误:

TypeError:试图分配给只读属性。MyTimer.js:35

我知道显示此错误是因为我使用的是严格模式,但我启用了严格模式来帮助我调试此对象。

创建MyTimer单例的调用是:

var simTimer = new SimTimer();

然后我添加一个要执行的任务,MyTimer如下所示:

var task = function(){
    console.log("performing task.");
};

simTimer.addTask(task);

最后,这是MyTimer对象(标记了第 35 行):

var MyTimer = (function () {
    "use strict";

    // var timer;
    var tasks;

    /**
     * If an instance of MyTimer exists, it will be saved to this variable and returned
     * by any subsequent calls to this constructor, thus only one instance (stored in this
     * variable) will be accessible.
     * @private
     */
    var instance;

    /**
     * Called to initialize this MyTimer Object, or return #instance if it already contains
     * an instance of this Object.
     */
    function Singleton() {
        if (instance) {
            return instance;
        }
        instance = this;
        tasks = $.Callbacks();
        this.timer = setInterval(function()
        {
            this.tasks.fire();
        }, 1000);//<---- THIS IS LINE 35!

        this.addTask = function(task)
        {
            this.tasks.add(task);
        };

        this.removeTask = function(task)
        {
            this.tasks.remove(task);
        };
    }

    //instance accessor
    Singleton.getInstance = function () {
        return instance || new Singleton();
    };

    return Singleton();

}());

我没有掌握什么?我已经阅读了很多关于Module Patterns的文档,并且之前已经成功编写过 Singletons - 那么我在这里哪里出错了?

** 编辑: **

我能够通过删除并在using中var tasks创建它来获得正确的行为。该函数的工作版本现在如下所示:Singletonthis

function Singleton() {
    if (instance) {
        return instance;
    }
    instance = this;

    this.tasks = $.Callbacks();

    this.timer = setInterval(function(){
        instance.tasks.fire();
    }, 1000);
    this.removeTask = function(task)
    {
        instance.tasks.remove(task);
    };
    this.addTask = function(task)
    {
        instance.tasks.add(task);
    };

}

所以我仍然不完全理解 - 为什么这个改变能解决它?毕竟是范围问题吗?

4

3 回答 3

1

如果我正确阅读了您的代码,那么您在此处遇到了范围问题

this.timer = setInterval(function()
{
    this.tasks.fire();  <-- this will be in window scope
}, 1000);

它应该是

this.timer = setInterval(function()
{
    instance.tasks.fire(); 
}, 1000);
于 2013-03-29T19:52:50.717 回答
1

我相信以下严格的模式限制是解释。

如果 this 在严格模式代码中进行评估,则 this 值不会被强制转换为对象。null 或 undefined 的 this 值不会转换为全局对象,原始值也不会转换为包装器对象。通过函数调用(包括使用 Function.prototype.apply 和 Function.prototype.call 进行的调用)传递的 this 值不会强制传递的 this 值到对象(10.4.3、11.1.1、15.3.4.3、15.3. 4.4)。

你打电话时

return Singleton();

this值实际上是未定义的。尝试这样做。

return {
    getInstance: function () {
        return instance || new Singleton();
    }
};
于 2013-03-29T20:14:25.383 回答
0

不确定这是否是原因,但看起来像“tasks = $.Callbacks();”的行 应该是“this.tasks = $.Callbacks();”。此外,当您提供一个实例作为回调时,您将失去“this”绑定。您使用“this”调用任何内容的函数体。应该改为使用在外部闭包中捕获它的 var(看起来像 'instance' 一样。

因此,例如,有问题的方法将显示为:

this.timer = setInterval(function() { instance.tasks.fire(); }, 1000);

于 2013-03-29T19:52:57.420 回答