Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to instantiate a Class from a String in JavaScript

I'm in a weird situation that i need to instantiate a new Class with a string stored in a variable but even i'm sure the class name is correct i get an error that given class name is not a constructor

Here is a dummy code that doesn't work:

class Foo {
    constructor(){
        console.log('Foo!');
    }
};
const foo = 'Foo';
const bar = new window[foo]();
console.log(bar);

This trow this error:

Uncaught TypeError: window[foo] is not a constructor
like image 671
penHolder Avatar asked Mar 01 '18 04:03

penHolder


People also ask

How do you instantiate a class in JavaScript?

An instance is an object containing data and behavior described by the class. The new operator instantiates the class in JavaScript: instance = new Class() . const myUser = new User(); new User() creates an instance of the User class.

Can we use class in JavaScript?

Classes are a template for creating objects. They encapsulate data with code to work on that data. Classes in JS are built on prototypes but also have some syntax and semantics that are not shared with ES5 class-like semantics.

What is a class constructor JavaScript?

A constructor is a special function that creates and initializes an object instance of a class. In JavaScript, a constructor gets called when an object is created using the new keyword. The purpose of a constructor is to create a new object and set values for any existing object properties.

Can a class return a value JavaScript?

The class constructor can return objects, but not primitive values.


1 Answers

One possibility is to use eval.

class Foo {
    constructor(){
        console.log('Foo!');
    }
};
const foo = 'Foo';
const bar = eval(`new ${foo}()`);
console.log(bar);

You will have to evaluate the safety of using eval() in your particular circumstances. If you know the origin of the string you are inserting into the code that you run eval() on or you can sanitize it first, then it may be safe.


I personally would prefer a lookup table. If you have a known number of classes that you want to map by string, then you can make your own lookup table and use that. This has the advantage of there can be no unintended consequences if the string has weird stuff in it:

class Foo {
    constructor(){
        console.log('Foo!');
    }
};

class Goo {
    constructor(){
        console.log('Goo!');
    }
};

// construct dict object that contains our mapping between strings and classes    
const dict = new Map([['Foo', Foo], ['Goo', Goo]]);

// make a class from a string
const foo = 'Foo';
let bar = new (dict.get(foo))()

console.log(bar);

If you were really going to go this route, you may want to encapsulate it in a function and then add error handling if the string is not found in the dict.

This should be better than using the global or Window object as your lookup mechanism for a couple reasons:

  1. If I recall, class definitions in ES6 are not automatically put on the global object like they would with other top level variable declarations (Javascript trying to avoid adding more junk on top of prior design mistakes).

  2. So, if you're going to manually assign to a lookup object, you might as well use a different object and not pollute the global object. That's what the dict object is used for here.

like image 125
jfriend00 Avatar answered Sep 19 '22 03:09

jfriend00