Use of .apply() with 'new' operator. Is this possible?

JavascriptOopClassInheritanceConstructor

Javascript Problem Overview


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

Javascript Solutions


Solution 1 - Javascript

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.

Solution 2 - Javascript

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:

function construct(constructor, args) {
    function F() {
        return constructor.apply(this, args);
    }
    F.prototype = constructor.prototype;
    return new F();
}

An object created by calling construct(Class, [1, 2, 3]) would be identical to an object created with new 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.

var createSomething = (function() {
    function F(args) {
        return Something.apply(this, args);
    }
    F.prototype = Something.prototype;

    return function(args) {
        return new F(args);
    }
})();

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:

function construct(constructor, args) {
    function F() : void {
        constructor.apply(this, args);
    }
    F.prototype = constructor.prototype;
    return new F();
}

Solution 3 - Javascript

If your environment supports ECMA Script 2015's spread operator (...), you can simply use it like this

function Something() {
    // init stuff
}

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

Note: Now that the ECMA Script 2015's specifications are published and most JavaScript engines are actively implementing it, this would be the preferred way of doing this.

You can check the Spread operator's support in few of the major environments, here.

Solution 4 - Javascript

Suppose you've got an Items constructor which slurps up all the arguments you throw at it:

function Items () {
    this.elems = [].slice.call(arguments);
}

Items.prototype.sum = function () {
    return this.elems.reduce(function (sum, x) { return sum + x }, 0);
};

You can create an instance with Object.create() and then .apply() with that instance:

var items = Object.create(Items.prototype);
Items.apply(items, [ 1, 2, 3, 4 ]);

console.log(items.sum());

Which when run prints 10 since 1 + 2 + 3 + 4 == 10:

$ node t.js
10

Solution 5 - Javascript

In ES6, Reflect.construct() is quite convenient:

Reflect.construct(F, args)

Solution 6 - Javascript

@Matthew I think it's better to fix the constructor property also.

// Invoke new operator with arbitrary arguments
// Holy Grail pattern
function invoke(constructor, args) {
    var f;
    function F() {
        // constructor returns **this**
        return constructor.apply(this, args);
    }
    F.prototype = constructor.prototype;
    f = new F();
    f.constructor = constructor;
    return f;
}

Solution 7 - Javascript

You could move the init stuff out into a separate method of Something's prototype:

function Something() {
    // Do nothing
}

Something.prototype.init = function() {
    // Do init stuff
};

function createSomething() {
    var s = new Something();
    s.init.apply(s, arguments);
    return s;
}

var s = createSomething(a,b,c); // 's' is an instance of Something

Solution 8 - Javascript

An improved version of @Matthew's answer. This form has the slight performance benefits obtained by storing the temp class in a closure, as well as the flexibility of having one function able to be used to create any class

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

This would be used by calling applyCtor(class, [arg1, arg2, argn]);

Solution 9 - Javascript

This answer is a little late, but figured anyone who sees this might be able to use it. There is a way to return a new object using apply. Though it requires one little change to your object declaration.

function testNew() {
	if (!( this instanceof arguments.callee ))
        return arguments.callee.apply( new arguments.callee(), arguments );
    this.arg = Array.prototype.slice.call( arguments );
    return this;
}

testNew.prototype.addThem = function() {
    var newVal = 0,
        i = 0;
    for ( ; i < this.arg.length; i++ ) {
        newVal += this.arg[i];
    }
    return newVal;
}

testNew( 4, 8 ) === { arg : [ 4, 8 ] };
testNew( 1, 2, 3, 4, 5 ).addThem() === 15;

For the first if statement to work in testNew you have to return this; at the bottom of the function. So as an example with your code:

function Something() {
    // init stuff
    return this;
}
function createSomething() {
    return Something.apply( new Something(), arguments );
}
var s = createSomething( a, b, c );

Update: I've changed my first example to sum any number of arguments, instead of just two.

Solution 10 - Javascript

I just came across this problem, and I solved it like this:

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

Yeah, it's a bit ugly, but it solves the problem, and it's dead simple.

Solution 11 - Javascript

if you're interested in an eval-based solution

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

Solution 12 - Javascript

This works!

var cls = Array; //eval('Array'); dynamically
var data = [2];
new cls(...data);

Solution 13 - Javascript

See also how CoffeeScript does it.

s = new Something([a,b,c]...)

becomes:

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

Solution 14 - Javascript

This constructor approach works both with and without the new keyword:

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;
}

It assumes support for Object.create but you could always polyfill that if you're supporting older browsers. See the support table on MDN here.

Here's a JSBin to see it in action with console output.

Solution 15 - Javascript

Solution without ES6 or polyfills:

var obj = _new(Demo).apply(["X", "Y", "Z"]);


function _new(constr)
{
    function createNamedFunction(name)
    {
        return (new Function("return function " + name + "() { };"))();
    }

    var func = createNamedFunction(constr.name);
    func.prototype = constr.prototype;
    var self = new func();

    return { apply: function(args) {
        constr.apply(self, args);
        return self;
    } };
}

function Demo()
{
    for(var index in arguments)
    {
        this['arg' + (parseInt(index) + 1)] = arguments[index];
    }
}
Demo.prototype.tagged = true;


console.log(obj);
console.log(obj.tagged);


output

Demo {arg1: "X", arg2: "Y", arg3: "Z"}


... or "shorter" way:

var func = new Function("return function " + Demo.name + "() { };")();
func.prototype = Demo.prototype;
var obj = new func();

Demo.apply(obj, ["X", "Y", "Z"]);


edit:
I think this might be a good solution:

this.forConstructor = function(constr)
{
    return { apply: function(args)
    {
        let name = constr.name.replace('-', '_');
        
        let func = (new Function('args', name + '_', " return function " + name + "() { " + name + "_.apply(this, args); }"))(args, constr);
        func.constructor = constr;
        func.prototype = constr.prototype;
        
        return new func(args);
    }};
}

Solution 16 - Javascript

You can't call a constructor with a variable number of arguments like you want with the new operator.

What you can do is change the constructor slightly. Instead of:

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

Do this instead:

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

Or if you must use an array:

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

Solution 17 - Javascript

Matthew Crumley's solutions in 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
)()

Solution 18 - Javascript

function createSomething() {
    var args = Array.prototype.concat.apply([null], arguments);
    return new (Function.prototype.bind.apply(Something, args));
}

If your target browser doesn't support ECMAScript 5 Function.prototype.bind, the code won't work. It is not very likely though, see compatibilty table.

Solution 19 - Javascript

modified @Matthew answer. Here I can pass any number of parameters to function as usual (not array). Also 'Something' is not hardcoded into:

function createObject( constr ) {   
  var args =  arguments;
  var wrapper =  function() {  
    return constr.apply( this, Array.prototype.slice.call(args, 1) );
  }

  wrapper.prototype =  constr.prototype;
  return  new wrapper();
}


function Something() {
    // init stuff
};

var obj1 =     createObject( Something, 1, 2, 3 );
var same =     new Something( 1, 2, 3 );

Solution 20 - Javascript

This one-liner should do it:

new (Function.prototype.bind.apply(Something, [null].concat(arguments)));

Solution 21 - Javascript

While the other approaches are workable, they're unduly complex. In Clojure you generally create a function that instantiates types/records and use that function as the mechanism for instantiation. Translating this to JavaScript:

function Person(surname, name){
  this.surname = surname;
  this.name = name;
}

function person(surname, name){ 
  return new Person(surname, name);
}

By taking this approach you avoid the use of new except as described above. And this function, of course, has no issues working with apply or any number of other functional programming features.

var doe  = _.partial(person, "Doe");
var john = doe("John");
var jane = doe("Jane");

By using this approach, all of your type constructors (e.g. Person) are vanilla, do-nothing constructors. You just pass in arguments and assign them to properties of the same name. The hairy details go in the constructor function (e.g. person).

It is of little bother having to create these extra constructor functions since they are a good practice anyhow. They can be convenient since they allow you to potentially have several constructor functions with different nuances.

Solution 22 - Javascript

It's also intresting to see how the issue of reusing the temporary F() constructor, was addressed by using arguments.callee, aka the creator/factory function itself: http://www.dhtmlkitchen.com/?category=/JavaScript/&date=2008/05/11/&entry=Decorator-Factory-Aspect

Solution 23 - Javascript

Any function (even a constructor) can take a variable number of arguments. Each function has an "arguments" variable which can be cast to an array with [].slice.call(arguments).

function Something(){
  this.options  = [].slice.call(arguments);

  this.toString = function (){
    return this.options.toString();
  };
}

var s = new Something(1, 2, 3, 4);
console.log( 's.options === "1,2,3,4":', (s.options == '1,2,3,4') );

var z = new Something(9, 10, 11);
console.log( 'z.options === "9,10,11":', (z.options == '9,10,11') );

The above tests produce the following output:

s.options === "1,2,3,4": true
z.options === "9,10,11": true

Solution 24 - Javascript

Here is my version of createSomething:

function createSomething() {
    var obj = {};
	obj = Something.apply(obj, arguments) || obj;
	obj.__proto__ = Something.prototype; //Object.setPrototypeOf(obj, Something.prototype); 
	return o;
}

Based on that, I tried to simulate the new keyword of JavaScript:

//JavaScript 'new' keyword simulation
function new2() {
    var obj = {}, args = Array.prototype.slice.call(arguments), fn = args.shift();
	obj = fn.apply(obj, args) || obj;
	Object.setPrototypeOf(obj, fn.prototype); //or: obj.__proto__ = fn.prototype;
	return obj;
}

I tested it and it seems that it works perfectly fine for all scenarios. It also works on native constructors like Date. Here are some tests:

//test
new2(Something);
new2(Something, 1, 2);

new2(Date);         //"Tue May 13 2014 01:01:09 GMT-0700" == new Date()
new2(Array);        //[]                                  == new Array()
new2(Array, 3);     //[undefined × 3]                     == new Array(3)
new2(Object);       //Object {}                           == new Object()
new2(Object, 2);    //Number {}                           == new Object(2)
new2(Object, "s");  //String {0: "s", length: 1}          == new Object("s")
new2(Object, true); //Boolean {}                          == new Object(true)

Solution 25 - Javascript

Yes we can, javascript is more of prototype inheritance in nature.

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;
};

when we create an object with "new" then our created object INHERITS getAge(), But if we used apply(...) or call(...) to call Actor, then we are passing an object for "this" but the object we pass WON'T inherit from Actor.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 with Actor...since we overwrite the prototype rather than the instance

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

Let's try with 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

By passing Actor.prototype to Actor.call() as the first argument, when the Actor() function is ran, it executes this.name=name, Since "this" will point to Actor.prototype, this.name=name; means Actor.prototype.name=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

Coming back to orginal question how to use new operator with apply, here is my take....

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

Solution 26 - Javascript

since ES6 this is possible through the Spread operator, see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_operator#Apply_for_new

This answer was already, sort of given in comment https://stackoverflow.com/a/42027742/7049810, but seems to have been missed by most

Solution 27 - Javascript

Actually the simplest method is:

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}

Solution 28 - Javascript

A revised solution from @jordancpaul's answer.

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

Solution 29 - Javascript

Make an anonymous prototype and apply the Something prototype to it using the arguments and then create a new instance of that anonymous prototype. The one disadavantage of this is it will not pass the s instanceof Something check, though it is identical, it is basically an instance of a clone.

function Something(){
    // init stuff
}
function createSomething(){
    return new (function(){Something.apply(this, arguments)});
}
var s = createSomething(a,b,c); // 's' is an instance of Something

Solution 30 - Javascript

Thanks to posts here I've used it this way:

SomeClass = function(arg1, arg2) {
	// ...
}

ReflectUtil.newInstance('SomeClass', 5, 7);

and implementation:

/**
 * @param strClass:
 *          class name
 * @param optionals:
 *          constructor arguments
 */
ReflectUtil.newInstance = function(strClass) {
	var args = Array.prototype.slice.call(arguments, 1);
	var clsClass = eval(strClass);
	function F() {
		return clsClass.apply(this, args);
	}
	F.prototype = clsClass.prototype;
	return new F();
};

Solution 31 - Javascript

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

Solution 32 - Javascript

As a late answer I though I would just drop this here as a more complete solution using many of the principals already outlined here.

Implements.js

To get you started, here is a basic usage:

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

Solution 33 - Javascript

why do you make the things so complex. After new use anonymous function which returns the constructor function with applied array with arguments.

function myConstructor(a,b,c){
    this.a = a;
    this.b = b;
    this.c = c;
}

var newObject = new myConstructor(1,2,3);	// {a: 1, b: 2, c: 3}

var myArguments = [1,2,3];
var anotherObject = new function(){
    return myConstructor.apply(this,myArguments);
  }; // {a: 1, b: 2, c: 3}

Solution 34 - Javascript

Shouldn't this work? Half-awake, didn't read closely.

var Storage = undefined;

return ((Storage = (new Something(...))) == undefined? (undefined) : (Storage.apply(...)));

Solution 35 - Javascript

This might be an inefficient way to approach this question, but I think it is straightforward enough for me to understand.

function createSomething(){
    // use 'new' operator to instantiate a 'Something' object
    var tmp = new Something(); 
    
    // If the interpreter supports [JavaScript 1.8.5][2], use 'Object.create'
    // var tmp = Object.create(Something.prototype); 

    // calling the constructor again to initialize the object
    Something.apply(tmp, arguments); 
    return tmp;
}

Solution 36 - Javascript

function F(a){this.a=a}
Z=F;
f=Function('return new function '+F.name+' ()
{return  Z.apply(this,[1]) } ').call()
console.log(f)

function F(a){this.a=a} 
f= new function(){return F.apply(this,[1])} 
console.log(f) 

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionPremView Question on Stackoverflow
Solution 1 - Javascriptuser123444555621View Answer on Stackoverflow
Solution 2 - JavascriptMatthew CrumleyView Answer on Stackoverflow
Solution 3 - JavascriptthefourtheyeView Answer on Stackoverflow
Solution 4 - JavascriptsubstackView Answer on Stackoverflow
Solution 5 - JavascriptgfacelessView Answer on Stackoverflow
Solution 6 - JavascriptwukongView Answer on Stackoverflow
Solution 7 - JavascriptTim DownView Answer on Stackoverflow
Solution 8 - JavascriptjordancpaulView Answer on Stackoverflow
Solution 9 - JavascriptTrevor NorrisView Answer on Stackoverflow
Solution 10 - JavascriptalekopView Answer on Stackoverflow
Solution 11 - Javascriptuser187291View Answer on Stackoverflow
Solution 12 - Javascriptinfinito84View Answer on Stackoverflow
Solution 13 - JavascriptmbarkhauView Answer on Stackoverflow
Solution 14 - JavascriptmuffinresearchView Answer on Stackoverflow
Solution 15 - JavascriptMartin WantkeView Answer on Stackoverflow
Solution 16 - JavascriptAnthony MillsView Answer on Stackoverflow
Solution 17 - JavascriptBenjieView Answer on Stackoverflow
Solution 18 - Javascriptuser2683246View Answer on Stackoverflow
Solution 19 - JavascriptEugen KonkovView Answer on Stackoverflow
Solution 20 - JavascriptaleembView Answer on Stackoverflow
Solution 21 - JavascriptMarioView Answer on Stackoverflow
Solution 22 - JavascriptpolarettoView Answer on Stackoverflow
Solution 23 - JavascriptWil Moore IIIView Answer on Stackoverflow
Solution 24 - JavascriptadvncdView Answer on Stackoverflow
Solution 25 - JavascriptThalaivarView Answer on Stackoverflow
Solution 26 - JavascriptPaulView Answer on Stackoverflow
Solution 27 - Javascriptuser3184743View Answer on Stackoverflow
Solution 28 - Javascripttech-eView Answer on Stackoverflow
Solution 29 - JavascriptDustin PoissantView Answer on Stackoverflow
Solution 30 - JavascriptMikeView Answer on Stackoverflow
Solution 31 - Javascriptuser2217522View Answer on Stackoverflow
Solution 32 - JavascriptMatthew.LothianView Answer on Stackoverflow
Solution 33 - JavascriptPawełView Answer on Stackoverflow
Solution 34 - JavascriptJohn HaugelandView Answer on Stackoverflow
Solution 35 - JavascriptRobb TsangView Answer on Stackoverflow
Solution 36 - JavascriptAlexeyP0708View Answer on Stackoverflow