When I want to call a function in javascript with arguments supplied from elsewhere I can use the apply method of the function like:
array = ["arg1", 5, "arg3"]
...
someFunc.apply(null, array);
but what if I need to call a constructor in a similar fashion? This does not seem to work:
array = ["arg1", 5, "arg3"]
...
someConstructor.apply({}, array);
at least not as I am attempting:
template = ['string1', string2, 'etc'];
var resultTpl = Ext.XTemplate.apply({}, template);
this does not work wither:
Ext.XTemplate.prototype.constructor.apply({}, template);
Any way to make that one work? (In this particular case I found that new Ext.XTemplate(template) will work, but I am interested in the general case)
similar question but specific to built-in types and without an answer I can use:
Instantiating a JavaScript object by calling prototype.constructor.apply
Thank you.
Edit:
Time has passed and ES6 and transpilers are now a thing.
In ES6 it is trivial to do what I wanted: new someConstructor(...array).
Babel will turn that into ES5 new (Function.prototype.bind.apply(someConstructor, [null].concat(array)))(); which is explained in How to construct JavaScript object (using ‘apply’)?.
There’s no simple, straightforward way to do this with a constructor function. This is because special things happen when you use the
newkeyword to call a constructor function, and so if you’re not going to do that, you have to emulate all of those special things. They are:prototypeproperty.constructorproperty.thisvalue (you’re doing that).I think that’s about it, but worth double-checking in the spec.
So if you can avoid it and just use the constructor function directly, I’d do that. 🙂 If you can’t, though, you can still do it, it’s just awkward and involves workarounds. (See also this related answer here on StackOverflow, although I cover all of the ground here [and then some] as well.)
Your biggest issue is #2 above: Setting the internal prototype of the object. For a long time, there was no standard way to do this. Some browsers supported a
__proto__property that did it, so you can use that if it’s there. The good news is that ECMAScript 5 introduces a way to do this explicitly:Object.create. So cutting-edge browsers like Chrome will have that. But if you’re dealing with a browser that has neitherObject.createnor__proto__, it gets a bit ugly:1) Define a custom constructor function.
2) Set its
prototypeproperty to theprototypeproperty of the real constructor function3) Use it to create a blank object instance.
That handles the prototype for you. Then you continue with:
4) Replace the
constructorproperty on that instance with the real constructor function.5) Call the real constructor function via
apply.6) If the return value of the real constructor function is an object, use it instead of the one you created; otherwise, use the one you created.
Something like this (live example):
You could take it a step further and only use the fake constructor if necessary, looking to see if
Object.createor__proto__are supported first, like this (live example):On Chrome 6, the above uses
Object.create; on Firefox 3.6 and Opera, it uses__proto__. On IE8, it uses the fake constructor function.The above is fairly off-the-cuff, but it mostly handles the issues I’m aware of in this area.