In JavaScript, I want to create an object instance (via the new
operator), but pass an arbitrary number of arguments to the constructor. Is this possible?
What I want to do is something like this (but the code below does not work):
function Something(){
// init stuff
}
function createSomething(){
return new Something.apply(null, arguments);
}
var s = createSomething(a,b,c); // 's' is an instance of Something
The Answer
From the responses here, it became clear that there's no built-in way to call .apply()
with the new
operator. However, people suggested a number of really interesting solutions to the problem.
My preferred solution was this one from Matthew Crumley (I've modified it to pass the arguments
property):
var createSomething = (function() {
function F(args) {
return Something.apply(this, args);
}
F.prototype = Something.prototype;
return function() {
return new F(arguments);
}
})();
I just came across this problem, and I solved it like this:
Yeah, it's a bit ugly, but it solves the problem, and it's dead simple.
Solution without ES6 or polyfills:
output
Demo {arg1: "X", arg2: "Y", arg3: "Z"}
... or "shorter" way:
edit:
I think this might be a good solution:
This one-liner should do it:
Yes we can, javascript is more of
prototype inheritance
in nature.when we create an object with "
new
" then our created object INHERITSgetAge
(), But if we usedapply(...) or call(...)
to call Actor, then we are passing an object for"this"
but the object we passWON'T
inherit fromActor.prototype
unless, we directly pass apply or call Actor.prototype but then.... "this" would point to "Actor.prototype" and this.name would write to:
Actor.prototype.name
. Thus affecting all other objects created withActor...
since we overwrite the prototype rather than the instanceLet's try with
apply
By passing
Actor.prototype
toActor.call()
as the first argument, when the Actor() function is ran, it executesthis.name=name
, Since "this" will point toActor.prototype
,this.name=name; means Actor.prototype.name=name;
Coming back to orginal question how to use
new operator with apply
, here is my take....modified @Matthew answer. Here I can pass any number of parameters to function as usual (not array). Also 'Something' is not hardcoded into:
Here's a generalized solution that can call any constructor (except native constructors that behave differently when called as functions, like
String
,Number
,Date
, etc.) with an array of arguments:An object created by calling
construct(Class, [1, 2, 3])
would be identical to an object created withnew Class(1, 2, 3)
.You could also make a more specific version so you don't have to pass the constructor every time. This is also slightly more efficient, since it doesn't need to create a new instance of the inner function every time you call it.
The reason for creating and calling the outer anonymous function like that is to keep function
F
from polluting the global namespace. It's sometimes called the module pattern.[UPDATE]
For those who want to use this in TypeScript, since TS gives an error if
F
returns anything: