483

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);
    }
})();
Prisoner ZERO
  • 13,848
  • 21
  • 92
  • 137
Prem
  • 15,911
  • 11
  • 31
  • 35
  • 2
    [Matthew Crumley's solution][1] in CoffeeScript: construct = (constructor, args) -> F = -> constructor.apply this,args F.prototype = constructor.prototype new F createSomething = (()-> F = (args) -> Something.apply this.args F.prototype = Something.prototype return -> new Something arguments )() [1]: http://stackoverflow.com/questions/1606797/use-of-apply-with-new-operator-is-this-possible/#1608546 – Benjie Sep 06 '11 at 14:28
  • 4
    I think the takeaway from this thread is that `new` does two things: (i) sets up the prototype, and (ii) applies that constructor with `this` set to the said object/prototype combo. You can make that happen either with `Object.create()`, or by rolling your own take on `Object.create()` and capturing context with a closure. – Dmitry Minkovsky Aug 11 '13 at 05:16
  • I generalized it by passing the class in as an argument into the outer function. So this is basically a factory-factory. – Killroy May 07 '14 at 14:23
  • The answer by @Pumbaa80 is seems better solution, and also used by ES6 Traceur to polyfill `spread` operator. =) Also it lil bit faster in Chrome: http://jsperf.com/dynamic-arguments-to-the-constructor – Sergey Kamardin Jul 29 '14 at 07:10
  • Can someone explain me why this guy couldn't do just like that `var s = new Something(a,b,c)` ? I can't get it :/ – through.a.haze Nov 24 '17 at 17:28
  • A little update from MDN: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_operator#Apply_for_new – Alwin Kesler Jan 04 '18 at 22:32

36 Answers36

387

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.

Unmitigated
  • 76,500
  • 11
  • 62
  • 80
user123444555621
  • 148,182
  • 27
  • 114
  • 126
  • 3
    You're right in saying that `Function.bind` can be used instead of `Function.prototype.bind`, I just left it for clarity. After all, any function could be used: `eval.bind` would save even more code, but that's really way too confusing. – user123444555621 Mar 23 '12 at 13:59
  • 1
    @Pumbaa80 My bad, reverted my edit. I tested `new (Function.prototype.bind.apply(Array, [1,2,3]));`, but forgot that your `newCall` function already receives a `cls` argument. – Rob W Mar 23 '12 at 14:00
  • @RobW No problem :) I think I'm gonna add a few explanatory words. – user123444555621 Mar 23 '12 at 14:12
  • 2
    Interesting, but important to remember that IE8 only supports [ECMAScript 3](http://kangax.github.com/es5-compat-table/) – jordancpaul Sep 08 '12 at 00:39
  • 3
    I found your solution very nice. but it is confusing. cuz in the first sample you wrote `newCall(Something, a, b, c);` where `a` would be the context for the bind but in the second example of yours you did mention did context is pointless - so you send `null`. for me it was very confusing ( would you believe me that I thought about it for 3 days?) - anyway your first code (to be persistent to your second example) needs to be : `function newCall(Cls) {var arr=Array.prototype.slice.call(arguments);arr.shift(); return new (Function.prototype.bind.apply(Cls, [null,arr]));` – Royi Namir Mar 11 '14 at 07:37
  • 4
    small fix : instead of `[null,arr]` - `[null].concat(arr)` – Royi Namir Mar 11 '14 at 07:57
  • @RoyiNamir Sure, it could be done that way, but in the end you have basically just replaced the first item of `arr` by `null`. And again, it could be anything. Why is `null` better than `Something`? Oh and don't worry: this is indeed a very complicated topic. It took me quite a while to figure it out, so 3 days is totally fine I guess – user123444555621 Mar 11 '14 at 08:15
  • +1 , :-) again just for consistency (first example vs second example). so beginners wont be confused. :-). you can just add remark. – Royi Namir Mar 11 '14 at 08:35
  • 1
    You did manage where most people failed: the object is of the correct type and I can later use `instanceof` etc. Thanks! – Wilt Mar 20 '14 at 16:52
  • jsfiddle with some tricks from the comments, and then some: http://jsfiddle.net/82aJR/1/ – zamnuts Mar 21 '14 at 05:00
  • I didn't see your answer and tried to re-invent the 'new' keyword :) See my answer below. – advncd May 13 '14 at 08:38
  • Vote for your answer cause its pretty good! Was used in my projects, and now wrote jsperf for it http://jsperf.com/dynamic-arguments-to-the-constructor =) – Sergey Kamardin Jul 29 '14 at 07:08
  • 1
    Bonus: this works with ES6 classes (tested in Node.js 4.0.0). With other methods you get an error that you can not call the constructor without new, but this works. Thanks. – bobef Sep 15 '15 at 11:32
  • Can you explain why the length of my first argument in **[this case](https://jsfiddle.net/wilt/yv1ck1cg/)** is not working correctly? It is very strange. – Wilt May 27 '16 at 13:13
  • For logging reasons, I'm trying to "wrap" a constructor and I am trying to use this answer to be able to pass an arbitrary number of arguments to the real constructor. But, this does not work for me and the reason it does not is that `Cls.bind.apply(Cls, arguments);` returns a new function that does not have the prototype that `Cls` does so I get a new object, but without the correct prototype. The Matthew Crumley answer below seems to address the prototype issue. – jfriend00 Jul 05 '16 at 00:59
  • The last note at the section ["Using apply to chain constructors"](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/apply#Using_apply_to_chain_constructors) mentions this same approach but adds **anyhow this is not the best way to do things and probably should not be used in any production environment**. I'm guessing that the prototype issue when wrapping is a reason. Are there any other reasons? – trss Oct 31 '16 at 20:47
  • The creation of a copy of the entire array of arguments looks like a stronger reason. – trss Nov 01 '16 at 07:20
  • This solved a problem of mine in creating a “new-less safe” constructor. It goes a little like this: `function Thing() { if(!(this instanceof Thing)) { var data=[null].concat(Array.prototype.slice.call(arguments)); return new (Thing.bind.apply(Thing,data)); } // regular constructor }`. – Manngo May 22 '17 at 12:02
  • 1
    Or the simpler version: ```function(...args) { return new myClass(...args); }``` – Pian0_M4n Jul 04 '17 at 07:22
  • You can also use bind like this: `let constr = A.bind(null, 'a', 'b', 'c'); let obj = new constr();` If the first parameter of bind, apply or call is empty, the this pointer inside the function reference always to window. – Martin Wantke Sep 03 '17 at 08:15
  • to go full meta: `function func(args,code){return newCall.apply(this,[Function].concat(args,[code]));}` and `func (["a","b"],"return a+b")(1,2)` ---> 3 – unsynchronized Jan 25 '20 at 04:51
  • Keep in mind this won't work in Chrome 49. But answer with spread operator works in Chrome 49 – Rustam Feb 02 '21 at 08:48
  • It's notable, that using new operator with a dynamic constructor is not useful, you can use a regular object factory instead. – Teemu Nov 09 '21 at 08:47
  • Destructuring assignment could make it even shorter: `new Cls.bind(null, ...args)()` – clarkttfu Jul 06 '23 at 13:39
260

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();
}
Mehran
  • 15,593
  • 27
  • 122
  • 221
Matthew Crumley
  • 101,441
  • 24
  • 103
  • 129
  • 2
    Thanks Matthew. Interesting to call a closure on the fly. Although your example shows the calling function allowing just one argument (an array of args), I guess this could be modified to have it pass on the `arguments` var instead. – Prem Oct 23 '09 at 11:04
  • There have been some excellent responses in this thread. I'm going to accept this one as my preferred solution, since it doesn't require modification of the original constructor (I didn't specify that as a requirement in my original question, but I appreciate it nevertheless). So the constructor can be written in any way, and the calling function written independently to add more convenience. – Prem Oct 24 '09 at 20:43
  • 2
    This doesn't work with `Date`, `String` or any other function that behaves differently when called as a constructor. – user123444555621 Jan 12 '12 at 13:37
  • @Pumbaa80 That's a good point. Native constructors know if they're being called as constructors or functions, so they behave differently in this case. – Matthew Crumley Jan 12 '12 at 15:37
  • 2
    Hi, Matthew, It's better to fix the constructor property aslo. An enhanced version of your answer. http://stackoverflow.com/a/13931627/897889 – wukong Dec 18 '12 at 11:57
  • This method doesn't work with some libraries which have their own weird inheritance code. For example with [KineticJS](http://stackoverflow.com/questions/14113667/how-does-the-inheritance-model-of-kineticjs-work). – AnnanFay Oct 19 '13 at 18:29
  • I don't understand why you need a new closure function every time when you instantiate a new class? That is crap, performance-wise – DATEx2 Feb 27 '14 at 09:41
  • 3
    One drawback is that the resulting constructed object `myObj.constructor.name` property will be set to `F` for everything. This kinda sucks when looking at stack traces and drilldown dumps inside of debuggers, because they use that name everywhere. – goat Mar 24 '14 at 17:49
  • You answer is great. However, I guess I have solved this with a simpler approach. Please take a look at my answer below and let me know what you think. – advncd May 13 '14 at 08:31
  • @DotNetWise I agree, no need for a closure function. Check out my answer below - it performs better and works with TypeScript as well since it doesn't require the constructor to return a value. – jordancpaul Feb 17 '16 at 21:45
37

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.

thefourtheye
  • 233,700
  • 52
  • 457
  • 497
  • 1
    This is a really nice solution. Also works for [this case](https://jsfiddle.net/wilt/yv1ck1cg/) where the solution of @user123444555621 fails. – Wilt May 27 '16 at 13:26
  • 3
    @Wilt: The JSFiddle must have `[null].concat(args)` instead of just `args` in the `bind.apply`. Check out the [fixed version](https://jsfiddle.net/yv1ck1cg/2/). – trss Nov 01 '16 at 05:49
  • @trss what is that additional null in the array doing? – Simon D Jun 26 '18 at 03:50
  • It's the `thisArg` mentioned at https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/apply. – trss Jun 27 '18 at 05:22
27

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
substack
  • 3,346
  • 24
  • 14
25

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

Reflect.construct(F, args)
gfaceless
  • 1,529
  • 1
  • 17
  • 22
  • I've been trying to understand how to use Reflect.construct to apply `this` to the new class I am constructing "F", but it seems like the context of `this` inside F is still new, and the old properties of `this` do not carry over, has anyone come across any good blog posts or examples of how to use `Reflect.construct()` ? – trickpatty Nov 04 '16 at 21:23
  • 1
    best answer here! – Thomas Wagenaar Mar 24 '17 at 18:29
  • This works for me - very nice! – lmiller1990 Apr 20 '23 at 04:21
9

@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;
}
wukong
  • 2,430
  • 2
  • 26
  • 33
  • I think you are right fixing the constructor is useful unless the application never checks it which cannot be implied when writing a library. – Jean Vincent Feb 07 '13 at 18:55
  • 1
    I have had a look at it in a debugger (evaluating `newObject.constructor == ConstructorFunction` at a breakpoint). Turns out that the assignment isn't needed at all, it is set correctly in the code of @MatthewCrumley. – hashchange Jan 23 '14 at 00:12
8

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
Tim Down
  • 318,141
  • 75
  • 454
  • 536
  • Yes, good idea. I could create an `init()` method and then use `apply()` on that. As with my comment on Ionut's approach, it's a bit of a shame that there's not a way to do this without modifying the architecture of the constructor. But this looks like a pragmatic solution. – Prem Oct 22 '09 at 16:22
8

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

jordancpaul
  • 2,954
  • 1
  • 18
  • 27
6

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.

alekop
  • 2,838
  • 2
  • 29
  • 47
6

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.

Trevor Norris
  • 20,499
  • 4
  • 26
  • 28
  • 1
    of course, arguments.callee is depreciated (https://developer.mozilla.org/en/JavaScript/Reference/Functions_and_function_scope/arguments/callee) but you can still just reference your constructor func directly by name – busticated Mar 24 '12 at 22:19
  • @busticated: absolutely correct, and I didn't use it in my second snippet. – Trevor Norris Mar 27 '12 at 23:04
  • 1
    The only problem with this solution is that it's going to end up running the constructor twice on the same object with different parameters. – Will Tomlins Nov 12 '12 at 14:40
  • 1
    @WillTomlins: It will end up running the constructor twice, and in a different context. Though I'm not sure how the parameters will have changed. Care to clarify? – Trevor Norris Nov 13 '12 at 19:19
  • 1
    I only meant that the object would be created, then the constructor would be run on that object without any parameters, then the constructor would be run again on the same object with in this case a, b & c. You might find some awkwardness comes out of this when your constructor requires certain parameters. – Will Tomlins Nov 16 '12 at 12:40
5

This works!

var cls = Array; //eval('Array'); dynamically
var data = [2];
new cls(...data);
infinito84
  • 1,971
  • 17
  • 8
  • Using Spread syntax,we can pass variable number of arguments to the constructor. Passing an iterable types like array as an argument and finally the array will expand to each parameters in the constructor. – Henok Tesfaye Jul 18 '18 at 08:47
4

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(",") + ")");
}
user187291
  • 53,363
  • 19
  • 95
  • 127
3

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(){});
mbarkhau
  • 8,190
  • 4
  • 30
  • 34
2

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.

muffinresearch
  • 380
  • 2
  • 10
2

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);
    }};
}
Martin Wantke
  • 4,287
  • 33
  • 21
1

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]);
Anthony Mills
  • 8,676
  • 4
  • 32
  • 51
  • OK, fair enough. This basically restricts the number of args to just one (either an object or an array), but allows an arbitrary number of properties within it. – Prem Oct 23 '09 at 10:57
  • Yes. Well, it doesn't restrict the number of args at all, really (you just use one of the args as a container for optional arguments), it's just that an object or an array are generally the most useful containers. You'll often see this pattern in constructors; it allows named parameters (good for self-documenting source code) as well as optional parameters. – Anthony Mills Oct 23 '09 at 12:28
1
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.

user2683246
  • 3,399
  • 29
  • 31
1

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 );
Eugen Konkov
  • 22,193
  • 17
  • 108
  • 158
1

This one-liner should do it:

new (Function.prototype.bind.apply(Something, [null].concat(arguments)));
aleemb
  • 31,265
  • 19
  • 98
  • 114
  • What is the difference to what @user123444555621 proposed? Can you add some explanation to the differences in your answer? – Wilt May 27 '16 at 13:25
1

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.

Mario
  • 6,572
  • 3
  • 42
  • 74
  • This isn't completely identical, since `arguments.length` will always be 2 inside your `Person` function, whereas instead using `new (Function.prototype.bind.apply(Person, arguments))` in `person` will set arguments to the correct value inside `Person` as well. – jsdw Oct 28 '16 at 14:08
1

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

Community
  • 1
  • 1
Paul
  • 335
  • 1
  • 3
  • 16
  • _Links to external resources are encouraged, but please add context around the link so your fellow users will have some idea what it is and why it’s there. Always quote the most relevant part of an important link, in case the target site is unreachable or goes permanently offline._ – Bugs Mar 08 '17 at 10:13
1

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
)()
Community
  • 1
  • 1
Benjie
  • 7,701
  • 5
  • 29
  • 44
0

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
Wil Moore III
  • 6,968
  • 3
  • 36
  • 49
  • This doesn't address the OP's question. Notice when you create vars `s` and `z` the number of args passed to `Something` is static. – jasonkarns Jun 13 '13 at 19:49
0

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)
advncd
  • 3,787
  • 1
  • 25
  • 31
  • Warning: The __proto__ property is deprecated and should not be used. Object.getPrototypeOf should be used instead of the __proto__ getter to determine the [[Prototype]] of an object. Mutating the [[Prototype]] of an object, no matter how this is accomplished, is strongly discouraged, because it is very slow and unavoidably slows down subsequent execution in modern JavaScript implementations. https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/proto – Michael Chernetsov Sep 24 '14 at 20:50
  • 1
    You are right about the proto object. That's why I have used Object.setPrototypeOf. And the whole thing is just a "simulation" of 'new' keyword. It clearly shows how JavaScript's new keyword works and how it actually instantiates the objects. – advncd Sep 25 '14 at 18:50
0

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);
Thalaivar
  • 23,282
  • 5
  • 60
  • 71
0

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}
user3184743
  • 111
  • 2
0

A revised solution from @jordancpaul's answer.

var applyCtor = function(ctor, args)
{
    var instance = new ctor();
    ctor.prototype.constructor.apply(instance, args);
    return instance;
}; 
tech-e
  • 434
  • 5
  • 15
0

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
Dustin Poissant
  • 3,201
  • 1
  • 20
  • 32
0

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

polaretto
  • 791
  • 9
  • 11
-1
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();
user2217522
  • 371
  • 3
  • 9
-1

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' }
Matthew.Lothian
  • 2,072
  • 17
  • 23
-1

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}
Paweł
  • 4,238
  • 4
  • 21
  • 40
-2

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;
}
Community
  • 1
  • 1
Robb Tsang
  • 89
  • 8
-2
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) 
-2

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

var Storage = undefined;

return ((Storage = (new Something(...))) == undefined? (undefined) : (Storage.apply(...)));
John Haugeland
  • 9,230
  • 3
  • 37
  • 40
-2

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();
};
Mike
  • 20,010
  • 25
  • 97
  • 140