With ECMAScript5's Function.prototype.bind
things get pretty clean:
function newCall(Cls) {
return new (Function.prototype.bind.apply(Cls, arguments));
// or even
// return new (Cls.bind.apply(Cls, arguments));
// if you know that Cls.bind has not been overwritten
}
It can be used as follows:
var s = newCall(Something, a, b, c);
or even directly:
var s = new (Function.prototype.bind.call(Something, null, a, b, c));
var s = new (Function.prototype.bind.apply(Something, [null, a, b, c]));
This and the eval-based solution are the only ones that always work, even with special constructors like Date
:
var date = newCall(Date, 2012, 1);
console.log(date instanceof Date); // true
edit
A bit of explanation:
We need to run new
on a function that takes a limited number of arguments. The bind
method allows us to do it like so:
var f = Cls.bind(anything, arg1, arg2, ...);
result = new f();
The anything
parameter doesn't matter much, since the new
keyword resets f
's context. However, it is required for syntactical reasons. Now, for the bind
call: We need to pass a variable number of arguments, so this does the trick:
var f = Cls.bind.apply(Cls, [anything, arg1, arg2, ...]);
result = new f();
Let's wrap that in a function. Cls
is passed as argument 0, so it's gonna be our anything
.
function newCall(Cls /*, arg1, arg2, ... */) {
var f = Cls.bind.apply(Cls, arguments);
return new f();
}
Actually, the temporary f
variable is not needed at all:
function newCall(Cls /*, arg1, arg2, ... */) {
return new (Cls.bind.apply(Cls, arguments))();
}
Finally, we should make sure that bind
is really what we need. (Cls.bind
may have been overwritten). So replace it by Function.prototype.bind
, and we get the final result as above.