让我们考虑简单的单例实现:
var singleton = function (Constructor) {
var singleton;
return function () {
if (!singleton) {
singleton = new Constructor();
}
return singleton;
};
};
我们可以将 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;
};
}());
答案 0 :(得分:4)
我们可以将单例变量的声明移到参数
首先,让我们可以通过在相同的几行代码中对两个完全不同的东西使用相同的符号(singleton
)来讨论这个问题而不用自己打结
这是你的第二个例子重命名:
var singleton = function (Constructor, instance) {
return function () {
if (!instance) {
instance = new Constructor();
}
return instance;
};
};
如果您这样做,那么使用两个参数调用singleton
函数将指定instance
,使Constructor
传递毫无意义 - Constructor
永远不会被{{singleton
调用1}}(再次,如果你传入两个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
。 (它也是另一种方式。)该链接具有较小但实际的运行时成本。
(在严格模式下,由于这个原因,没有链接。)
答案 1 :(得分:1)
就closure
而言,这两种实现没有区别。但是,在第一个示例中,调用者无法设置单例。
我将在两个实现之间做出选择,只是基于是否可以在这些示例函数之外创建单例。如果可以,请使用model 2
,否则请使用model 1