James Craig
James Craig

Reputation: 6854

Dynamically Instantiate a Function & Call a Method in JavaScript

Take this JavaScript class:

var Foo = function() {

    this.bar = function() {
        return 'foobar';
    };

};

I can instantiate this class and call it's bar method like this:

(new Foo).bar();

I would like to achieve the instantiation and calling of the class and it's method dynamically based of a string that represents a class and method like Foo@bar.

I have tries the following to achieve this but receive the error Uncaught TypeError: string is not a function:

var action = 'Foo@bar';
var classMethod = action.split('@');

(new classMethod[0]).call(classMethod[1]);

Is this even possible in JavaScript or am I going about this in the wrong way?

Upvotes: 0

Views: 105

Answers (4)

Oriol
Oriol

Reputation: 288080

classMethod[0] is a string, so you can't use it as a constructor.

Assuming Foo is a global function,

new window[classMethod[0]]()[classMethod[1]]();

Upvotes: 0

Nicholas Daley-Okoye
Nicholas Daley-Okoye

Reputation: 2397

You could do something with eval. But I won't show that because eval is evil.

If you are willing to create an object containing the types that can be created:

var Foo = function() {
    this.bar = function() {
        return 'foobar';
    };
};  
var types = {
    Foo : Foo
};

var action = 'Foo@bar';
var classMethod = action.split('@');

(new types[classMethod[0]])[classMethod[1]]();

The problem with your code was that classMethod[0] is a string. But to use new you need to give it a function. In my code I make use of javascript's [] operators which accesses properties of an object using a string containing the property's name. First I use it to get the Foo property from the types object. This is your constructor. Then after calling the constructor, I use the [] operators again to get the bar property.

Upvotes: 1

Bartosz Gościński
Bartosz Gościński

Reputation: 1580

To access constructor by names you need to have it accessible in some collection. For example:

var Foo = function() {
    this.bar = function() {
        return 'foobar';
    };
};

var constructors = {
  Foo: Foo,
  Bar: Bar
};

function instantiateAndInvoke(action) {
  var classMethod = action.split('@');
  var constr = constructors[classMethod[0]];
  var instance = new constr();

  return instance[classMethod[1]]();
}

// and then
var result = instantiateAndInvoke('Foo@bar');

Upvotes: 0

deadboy
deadboy

Reputation: 859

Assuming you have a Foo object

var foo = new Foo();

You can say foo["bar"](); to call a method called bar on it.

Upvotes: 0

Related Questions