views:

168

answers:

3

How can I instantiate a class by throwing in a variable name? Consider this method inside a class:

animate: function(el, build) { 
        console.log(build.effect); 
        var animationClass = new build.effect(el,build); 
},

Build is an object containing lots of stuff, but most importantly an "effect". This effect is the name of an independent animation class-- one is called "MarioKartMenu".

console.log(build.effect) prints out "MarioKartMenu". But of course I get: TypeError: Result of expression 'build.effect' [MarioKartMenu] is not a constructor.

If I trash the dynamism and just make the code as such:

animate: function(el, build) {
     var animationClass = new MarioKartMenu(el,build);
    },

It works just fine. Is it possible to make it dynamic like I'm attempting to do?

+1  A: 

If the function MarioKartMenu is defined in the global scope, you can access it by its string name using:

window["MarioKartMenu"]

This works because all global variables are properties of the window object.

Given the above, you can implement what you want by using:

var menuConstructor = window[build.effect];
var animationClass = new menuConstructor(el, build);
Ayman Hourieh
Perfect, I had it a feeling it would look something like that. Thank you.
rpflo
A: 

My first thought is to use JavaScript's eval() operator, though I understand this is a less than elegant solution. (Soemthing like this: var animationClass = eval("new "+build.effect+"(el, build)"); although I'm not sure that's correct as I haven't used eval() like this before.). Ayman's answer is a much better variation on this idea.

My second thought is that MarioKartMenu isn't suitably abstracted. So I'd build a simple class around it that takes the effect name as a third parameter and uses a switch() statement to select amongst all the available effects, instantiates the correct one and returns it.

staticsan
Good suggestions. In the end I have no idea what effects will be there, as the class calling the animation classes will be completely extendable to allow anybody to create and use their own animations. So a switch statement wouldn't work.
rpflo
+1  A: 

Just assign the constructor to build.effect (not a string containing it's name) and it should work:

animate = function(el, build) {
    var animationClass = new build.effect(el,build);
}
// ...

b = ...;
b.effect = MarioKartMenu;
animate(e, b);
sth
Also good to know, but once again, I have no idea what others might name their animation classes, so I'd still be dealing with a string. Perhaps I'm misunderstanding what you're saying though.
rpflo
Somewhere the users of your class need to specify which effect to use. Can't they there give you the constructor function itself instead of a string with the constructor functions name in it?I'm not sure how the interface is going to look like, but it seems like a user would do something like this: var FooMenu = {...}; setEffect("FooMenu");. I would suggest to not use a string but pass FooMenu directly: var FooMenu = {...}; setEffect(FooMenu);.
sth
Very valid. I'm going to explore this.
rpflo