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

当前回答

我遇到了这个问题,我是这样解决的:

function instantiate(ctor) {
    switch (arguments.length) {
        case 1: return new ctor();
        case 2: return new ctor(arguments[1]);
        case 3: return new ctor(arguments[1], arguments[2]);
        case 4: return new ctor(arguments[1], arguments[2], arguments[3]);
        //...
        default: throw new Error('instantiate: too many parameters');
    }
}

function Thing(a, b, c) {
    console.log(a);
    console.log(b);
    console.log(c);
}

var thing = instantiate(Thing, 'abc', 123, {x:5});

是的,这有点丑,但它解决了问题,而且非常简单。

其他回答

你不能像new操作符那样调用带有可变数量参数的构造函数。

你能做的就是稍微改变构造函数。而不是:

function Something() {
    // deal with the "arguments" array
}
var obj = new Something.apply(null, [0, 0]);  // doesn't work!

你可以这样做:

function Something(args) {
    // shorter, but will substitute a default if args.x is 0, false, "" etc.
    this.x = args.x || SOME_DEFAULT_VALUE;

    // longer, but will only put in a default if args.x is not supplied
    this.x = (args.x !== undefined) ? args.x : SOME_DEFAULT_VALUE;
}
var obj = new Something({x: 0, y: 0});

或者如果你必须使用数组:

function Something(args) {
    var x = args[0];
    var y = args[1];
}
var obj = new Something([0, 0]);

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

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

其实最简单的方法是:

function Something (a, b) {
  this.a = a;
  this.b = b;
}
function createSomething(){
    return Something;
}
s = new (createSomething())(1, 2); 
// s == Something {a: 1, b: 2}

是的,我们可以,javascript在本质上更多的是原型继承。

function Actor(name, age){
  this.name = name;
  this.age = age;
}

Actor.prototype.name = "unknown";
Actor.prototype.age = "unknown";

Actor.prototype.getName = function() {
    return this.name;
};

Actor.prototype.getAge = function() {
    return this.age;
};

当我们创建一个带有"new"的对象时,我们创建的对象继承getAge(),但如果我们使用apply(…)或call(…)来调用Actor,那么我们为"this"传递了一个对象,但我们传递的对象不会继承自Actor.prototype

除非,我们直接通过apply或调用Actor。原型但是....“this”指向“Actor”。this.name将写入:actor。prototype.name。从而影响所有用Actor创建的其他对象…因为我们覆盖的是原型而不是实例

var rajini = new Actor('Rajinikanth', 31);
console.log(rajini);
console.log(rajini.getName());
console.log(rajini.getAge());

var kamal = new Actor('kamal', 18);
console.log(kamal);
console.log(kamal.getName());
console.log(kamal.getAge());

让我们试试apply

var vijay = Actor.apply(null, ["pandaram", 33]);
if (vijay === undefined) {
    console.log("Actor(....) didn't return anything 
           since we didn't call it with new");
}

var ajith = {};
Actor.apply(ajith, ['ajith', 25]);
console.log(ajith); //Object {name: "ajith", age: 25}
try {
    ajith.getName();
} catch (E) {
    console.log("Error since we didn't inherit ajith.prototype");
}
console.log(Actor.prototype.age); //Unknown
console.log(Actor.prototype.name); //Unknown

通过传递Actor。prototype to Actor.call()作为第一个参数,当Actor()函数运行时,它执行this.name=name,因为“this”将指向Actor。原型,this.name =名称;意味着Actor.prototype.name =名称;

var simbhu = Actor.apply(Actor.prototype, ['simbhu', 28]);
if (simbhu === undefined) {
    console.log("Still undefined since the function didn't return anything.");
}
console.log(Actor.prototype.age); //simbhu
console.log(Actor.prototype.name); //28

var copy = Actor.prototype;
var dhanush = Actor.apply(copy, ["dhanush", 11]);
console.log(dhanush);
console.log("But now we've corrupted Parent.prototype in order to inherit");
console.log(Actor.prototype.age); //11
console.log(Actor.prototype.name); //dhanush

回到最初的问题,如何使用新的操作符与应用,这里是我的....

Function.prototype.new = function(){
    var constructor = this;
    function fn() {return constructor.apply(this, args)}
    var args = Array.prototype.slice.call(arguments);
    fn.prototype = this.prototype;
    return new fn
};

var thalaivar = Actor.new.apply(Parent, ["Thalaivar", 30]);
console.log(thalaivar);
function FooFactory() {
    var prototype, F = function(){};

    function Foo() {
        var args = Array.prototype.slice.call(arguments),
            i;     
        for (i = 0, this.args = {}; i < args.length; i +=1) {
            this.args[i] = args[i];
        }
        this.bar = 'baz';
        this.print();

        return this;
    }

    prototype = Foo.prototype;
    prototype.print = function () {
        console.log(this.bar);
    };

    F.prototype = prototype;

    return Foo.apply(new F(), Array.prototype.slice.call(arguments));
}

var foo = FooFactory('a', 'b', 'c', 'd', {}, function (){});
console.log('foo:',foo);
foo.print();