我编写了以下函数,允许从给定的类创建单例类:
function SingletonFrom(Constructor) {
return function() {
var self = arguments.callee;
if (self._instance === undefined) {
switch (arguments.length) { // this is ugly
case 0: self._instance = new Constructor(); break;
case 1: self._instance = new Constructor(arguments[0]); break;
case 2: self._instance = new Constructor(arguments[0], arguments[1]); break;
// [...]
case 10: // ...
default: throw new Error('Error in Singleton: Constructor may take at most 10 arguments'); break;
}
}
return self._instance;
}
}
示例:
var Array_Singleton = new SingletonFrom(Array);
var x = new Array_Singleton(1,2,3); // [1,2,3]
var y = new Array_Singleton(0,0,0,0); // [1,2,3]
alert(x === y); // true
效果很好,但我对switch
语句不太满意。问题是将可变数量的参数传递给使用“new
”关键字调用的构造函数是不可能的。因此,我的构造函数不能超过10个参数。例如,这将失败:
new Array_Singleton(1,2,3,4,5,6,7,8,9,10,11);
有什么方法可以解决这个问题吗?
答案 0 :(得分:1)
Javascript有这种烦人的限制无法使用数组作为参数列表调用构造函数。当函数作为函数调用时,Function.prototype.apply
通常可以实现的功能(例如foo(...)
),当它被称为构造函数(例如new foo(...)
)时,不能轻易地应用于函数。
我猜这正是你在那里诉诸switch
的原因。
function foo(a,b) {
return a+b;
}
foo.apply(null, [1,2]); // 3
但构造函数不是那么容易:
function Person(fname, lname) {
this.fname = fname;
this.lname = lname;
}
Person.prototype.speak = function() {
return 'Hi. My name is: ' + this.fname + ' ' + this.lname;
}
new Person.apply(null, ['John', 'Appleseed']); // doesn't work!
要解决这个问题,您可以创建一个简单的帮助程序,实际上模拟new
做什么,这次仅使用apply
。该算法很简单:
apply
在这个新创建的对象的上下文中调用构造函数,并使用apply
传递参数列表。它看起来像这样:
function newApply(ctr, array) {
function F(){}
F.prototype = ctr.prototype;
var obj = new F();
ctr.apply(obj, array);
return obj;
}
newApply(Person, ['John', 'Appleseed']); // returns new object
或者,您可以避免在运行时创建F
对象以节省性能和内存消耗:
var newApply = (function(){
function F(){}
return function(ctr, array) {
F.prototype = ctr.prototype;
var obj = new F();
ctr.apply(obj, array);
return obj;
}
})();
答案 1 :(得分:0)
在我的头脑中,我只能想到一个,如果没有非常大量的测试,我可能不会推荐它。
有人说;而不是单独传递参数,将它们作为数组传递。然后,您可以遍历数组并在调用new
时构建一个字符串。获得字符串后,可以调用eval()
来运行生成的命令。
这将为您提供处理任何动态数量参数的方法。