在JavaScript中,我想创建一个对象实例(通过new操作符),但将任意数量的参数传递给构造函数。这可能吗?
我想做的是这样的(但下面的代码不起作用):
function Something(){
// init stuff
}
function createSomething(){
return new Something.apply(null, arguments);
}
var s = createSomething(a,b,c); // 's' is an instance of Something
这个问题的答案
从这里的响应可以清楚地看出,没有内置的方法可以使用new操作符调用.apply()。然而,人们对这个问题提出了许多非常有趣的解决方案。
我更喜欢的解决方案是来自Matthew Crumley的这个(我修改了它来传递arguments属性):
var createSomething = (function() {
function F(args) {
return Something.apply(this, args);
}
F.prototype = Something.prototype;
return function() {
return new F(arguments);
}
})();
假设你有一个Items构造函数,它吸收了你给它的所有参数:
function Items () {
this.elems = [].slice.call(arguments);
}
Items.prototype.sum = function () {
return this.elems.reduce(function (sum, x) { return sum + x }, 0);
};
你可以用Object.create()创建一个实例,然后用.apply()创建该实例:
var items = Object.create(Items.prototype);
Items.apply(items, [ 1, 2, 3, 4 ]);
console.log(items.sum());
当运行时输出10,因为1 + 2 + 3 + 4 == 10:
$ node t.js
10
这种构造函数方法在使用或不使用new关键字时都有效:
function Something(foo, bar){
if (!(this instanceof Something)){
var obj = Object.create(Something.prototype);
return Something.apply(obj, arguments);
}
this.foo = foo;
this.bar = bar;
return this;
}
它假设支持Object。创建,但如果你支持旧的浏览器,你总是可以填充它。请参阅MDN上的支持表。
下面是一个JSBin,可以看到它在控制台输出中的作用。
Matthew Crumley在CoffeeScript中的解决方案:
construct = (constructor, args) ->
F = -> constructor.apply this, args
F.prototype = constructor.prototype
new F
or
createSomething = (->
F = (args) -> Something.apply this, args
F.prototype = Something.prototype
return -> new Something arguments
)()