17

Apart from eval(`o = new ${className}(${args.join(", ")})`), is there any other way to instantiate an object using variable argument list?

E.g.: var foo = instantiate(className, [arg1, arg2, ...])

3 Answers 3

19

You can instantiate an object with a variable argument list like this:

function instantiate(className, args) {
    var o, f, c;
    c = window[className]; // get reference to class constructor function
    f = function(){}; // dummy function
    f.prototype = c.prototype; // reference same prototype
    o = new f(); // instantiate dummy function to copy prototype properties
    c.apply(o, args); // call class constructor, supplying new object as context
    o.constructor = c; // assign correct constructor (not f)
    return o;
}

Side note: you may wish to pass a direct reference to the class constructor function:

var foo = instantiate(Array, [arg1, arg2, ...]);
// Instead of:
var foo = instantiate("Array", [arg1, arg2, ...]);

... which makes this compatible with non-global functions.

Sign up to request clarification or add additional context in comments.

5 Comments

window[className] is undefined for me (yeah, triple checked my class name).
TypeError: c is undefined because (window[className] is undefined )
Instead of c.apply(o, args), I think it should be c.constructor.apply(o, args). Else error occurs as "Class constructor must be invoked with 'new' operator.".
Probably if you are using node (not doing it inside of a browser) the window object will be undefined...
window works in ES5 but not on ES6, the answer date is from 2011, don't expect that to work today...
6

Using Object.create() in ES5:

function instantiate(constructor, args) {
    var instance = Object.create(constructor.prototype);
    constructor.apply(instance, args);
    return instance;
}

Using the spread operator in ES6:

var foo = new constructor(...args);

9 Comments

Something tells me this will be four times faster than the accepted answer.
@inetphantom the first or the second one?
Downvoted because this answer requires using a type literal, which is antithetical to the question’s premise.
@user1944491 what even is a "type literal"?
@AlexeyLebedev In the statement let m = new Map() the word Map is a type literal. You can clearly see in the OP’s question that he wants dynamic types, not static predetermined types.
|
-1

Well you can always do as follows. Anything added to Dino prototype can be shared among the instantiated objects The difference from normal constructor pattern is, the instantiated objects do not have to have the exact same private properties set. They can be set dynamically for each one of them.

function Dino(a,b){
  for(i = 0; i< a.length; i++) this[a[i]] = b[i];
}

var props = ["foo", "bar"],
   values = [42, 37],
      obj = new Dino(props,values);
console.log(obj);

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.