在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);
    }
})();

当前回答

作为一个迟来的回答,我想我只是把它放在这里作为一个更完整的解决方案,使用了这里已经概述的许多原则。

Implements.js

首先,这里有一个基本用法:

var a = function(){
    this.propa = 'a';
}
var b = function(){
    this.propb = 'b'
}
var c = Function.Implement(a, b); // -> { propa: 'a', propb: 'b' }

其他回答

看看CoffeeScript是如何做到的。

([a,b,c]…)

就变成:

var s;
s = (function(func, args, ctor) {
  ctor.prototype = func.prototype;
  var child = new ctor, result = func.apply(child, args);
  return Object(result) === result ? result : child;
})(Something, [a, b, c], function(){});

如果您对基于求值的解决方案感兴趣

function createSomething() {
    var q = [];
    for(var i = 0; i < arguments.length; i++)
        q.push("arguments[" + i + "]");
    return eval("new Something(" + q.join(",") + ")");
}

如果您的环境支持ECMA Script 2015的扩展操作符(…),您可以像这样简单地使用它

function Something() {
    // init stuff
}

function createSomething() {
    return new Something(...arguments);
}

注意:现在ECMA Script 2015的规范已经发布,大多数JavaScript引擎都在积极地实现它,这将是最好的方式。

您可以在这里查看在一些主要环境中对扩展操作符的支持。

@jordancpaul的答案修改后的解决方案。

var applyCtor = function(ctor, args)
{
    var instance = new ctor();
    ctor.prototype.constructor.apply(instance, args);
    return instance;
}; 

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
)()