JavaScript单例类型错误:为什么严格模式会标记这个

JavaScript singleton type-error: why does strict mode flag this?

本文关键字:模式 类型 单例 错误 为什么 JavaScript      更新时间:2023-09-26

我对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();
}());

我有什么没有领会?我已经阅读了很多关于模块模式的文档,并且已经成功地编写了单例——那么我在这里错在哪里呢?

** EDIT: **

我能够通过删除var tasks来获得正确的行为,并使用thisSingleton中创建它。函数的工作版本现在看起来像这样:

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

所以我仍然不完全理解-为什么这个改变修复了它?这到底是一个范围问题吗?

如果我没看错的话,这里有一个作用域问题

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

应该是

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

我认为以下严格的模式限制是解释。

如果在严格模式代码中求值,则this值为没有被强制到一个对象上。如果此值为空或未定义,则不是转换为全局对象,并且不转换原始值包装对象。this值通过函数调用传递(包括使用Function.prototype.apply和Function.prototype.call)不会强制传递这个值给对象(10.4.3,11.1.1,15.3.4.3,15.3.4.4).

当你呼叫

return Singleton();

this值实际上是未定义的。

return {
    getInstance: function () {
        return instance || new Singleton();
    }
};

不确定这是否是原因,但看起来"tasks = $. callbacks();"应该是"this"。tasks = $. callbacks ();此外,当您提供一个实例作为回调时,您将丢失'this'绑定。你调用任何带有"this."的函数体应该使用一个var来在外部闭包中捕获它(看起来像'instance'所做的)。

例如,这个方法应该是:

。timer = setInterval(函数){instance.tasks.fire ();}, 1000);