1

让我们考虑简单的单例实现:

var singleton = function (Constructor) {
    var singleton;
    return function () {
        if (!singleton) {
            singleton = new Constructor();
        }
        return singleton;
    };
};

我们可以将单例变量的声明移至参数:

var singleton = function (Constructor, singleton) {
    return function () {
        if (!singleton) {
            singleton = new Constructor();
        }
        return singleton;
    };
};

所以我只是对副作用感到好奇。

再举一个例子:

var counter = (function (i) {
    return function () {
        i = (i || 0) + 1;
        return i;
    };
}());
4

2 回答 2

4

我们可以将单例变量的声明移至参数

首先,让我们通过在相同的几行代码中singleton对两个完全不同的事物使用相同的符号 ( ) 来讨论这个问题而不用纠结。

这是您重命名的第二个示例:

var singleton = function (Constructor, instance) {
    return function () {
        if (!instance) {
            instance = new Constructor();
        }
        return instance;
    };
};

如果你这样做了,那么singleton用两个参数调用函数将指定instance,从而使传入Constructor毫无意义——Constructor永远不会被调用singleton(再次,如果你传入两个 args [并且第二个 arg 是真实的])。所以这样做会有点奇怪。

但是你问了副作用。如果您分配给函数内的正式参数,则不会涉及任何外部影响。例如,它在函数之外没有任何影响:

function foo(arg) {
    arg = 67;
}
var a = 42;
foo(a);
console.log(a); // Still 42

但是,在非严格模式下,分配给一个参数而不是一个局部变量确实有一个小的成本,因为涉及到开销:它与魔术arguments伪数组有关。在非严格模式下,函数的形式参数和arguments伪数组之间存在联系:

function foo(a, b) {
    console.log(a);
    console.log(b);
    b = 42;
    console.log(arguments[1]);
}

如果我们这样称呼它:

foo(1, 2);

我们看

1
2
42

请注意魔术:分配给形式参数会b更新伪数组arguments。(它也以另一种方式工作。)该链接具有很小但实际的运行时成本。

(在严格模式下,没有链接,正因如此。)

于 2013-08-07T09:08:35.667 回答
1

就目前closure而言,这两种实现方式没有区别。但是,在第一个示例中,调用者不能设置单例。

我将在这两种实现之间进行选择,这取决于是否可以在这些示例函数之外创建单例。如果可以,请使用,model 2否则使用model 1

于 2013-08-07T09:12:52.050 回答