0

我编写了以下函数,允许从给定类创建单例类:

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”关键字调用的构造函数是不可能的。所以,我的 Constructor 函数不能接受超过 10 个参数。例如,这将失败:

new Array_Singleton(1,2,3,4,5,6,7,8,9,10,11);

有什么办法可以解决这个问题?

4

2 回答 2

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!

要解决这个问题,您可以创建一个简单的帮助程序,它实际上可以模拟newapply. 该算法很简单:

  1. 使用适当的原型链创建一个空对象,但不要在其上调用构造函数。
  2. 用于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;
  }
})();
于 2009-09-23T13:53:21.733 回答
0

在我的脑海中,我只能想到一个,如果没有大量的测试,我可能不会推荐它。

话虽如此; 而不是单独传递参数,而是将它们作为数组传递。然后,您可以遍历数组并通过调用来构建一个字符串new。一旦你有了你的字符串,你可以调用eval()来运行你生成的命令。

这将为您提供一种处理任何动态参数数量的方法。

于 2009-09-23T13:10:11.640 回答