4

The problem is that I need to create a new instance of the passed class

Is there a way to rewrite this function, so it could accept any number of arguments?

function createInstance(ofClass, arg1, arg2, arg3, ..., argN){
  return new ofClass(arg1, arg2, arg3, ..., argN);
}

This function should create an instance of the passed class. Example:

var SomeClass = function(arg1, arg2, arg3){
   this.someAttr = arg3;
   .....
}
SomeClass.prototype.method = function(){}

var instance = createInstance(SomeClass, 'arg1', 'arg2', 'arg3'); 

So this should be true.

instance instanceof SomeClass == true  

Right now, I've just limited N to 25, with hope that more arguments are rarely used.

  • 1
    Did you read John Resig's article (linked below)? It'll do what you want (although you will need some extra code to do it, of course.) I can't think of any other way to simulate a call to `new`. The way Resig explains it is what I've seen in all JavaScript libraries with dynamic class generation (MooTools for example.) – Blixt Aug 13 '09 at 13:50
  • Thank you, I will go with your solution. –  Aug 13 '09 at 13:54
  • This has the correct answer: http://stackoverflow.com/questions/5054926/javascript-create-instance-with-array-of-arguments – Ephraim Tabackman Jul 25 '12 at 10:49

2 Answers2

10

The other answers are on the right track, but none of them mention that you have to be aware of the fact that arguments is not an Array. It's a special structure that behaves like an Array.

So before you use it like an Array, you can convert it to one like this:

function createInstance(cls) {
    // This will use the slice function of the Array type, effectively converting
    // the arguments structure to an Array and throwing away the first argument,
    // which is cls.
    var args = Array.prototype.slice.call(arguments, 1);
    return cls.apply(this, args);
}

Sorry, I just copied the code with constructor etc. and didn't think about what it would actually do. I've updated it now to what you want. You'll find that it's calling the constructor without new, so you won't get the same behavior. However, John Resig (author of jQuery) wrote on this very issue.

So based on John Resig's article you've got two ways to solve it. The more elaborate solution will be the most transparent to the user, but it's up to you which solution you choose.


Here is a "perfect" solution if you only intend to support browsers that have the Object.create function (which is a pretty big percentage now compared to three years ago):

function createInstance(cls) {
    var obj = Object.create(cls.prototype);

    var args = Array.prototype.slice.call(arguments, 1);
    cls.apply(obj, args);

    return obj;
}

The resulting objects from both new cls(x) and createInstance(cls, x) should be identical.

Blixt
  • 49,547
  • 13
  • 120
  • 153
  • Sorry, my question wasn't clear enough, the problem is that I need a new instance of obj, so your answer doesn't solve my problem, but upvoted for mention that arguments in not an Array. –  Aug 13 '09 at 13:15
  • I understand your question better now. Read my update for how to solve your problem. – Blixt Aug 13 '09 at 13:17
  • 1
    I'd appreciate an explanation for -1, especially considering that this is the only answer that, to the best of my knowledge, works (when taking John Resig's change into consideration.) I see someone finally brought up `eval` as a solution, but I wouldn't touch that with a stick, I'm afraid. – Blixt Aug 13 '09 at 13:33
4

There is always an arguments array

Tim Büthe
  • 62,884
  • 17
  • 92
  • 129
  • I know about it, please give an example how would you use it to rewrite this function. –  Aug 13 '09 at 12:37
  • Could you give a concrete example? Do you have to pass all args in the constructor? Doesn't Djko's Answer work? http://stackoverflow.com/questions/1271657/javascript-factory-with-optional-arguments/1271673#1271673 – Tim Büthe Aug 13 '09 at 12:42