How do I make JavaScript Object using a variable String to define the class name?

Viewed 98923

Here's what I'm trying to do -- this is pseudo code and doesn't work. Does anyone know how to accomplish this for real:

// Define the class
MyClass = Class.extend({});

// Store the class name in a string
var classNameString = 'MyClass';

// Instantiate the object using the class name string
var myObject = new classNameString();
10 Answers

Here's a more robust solution that will work with namespaced functions:

var stringToFunction = function(str) {
  var arr = str.split(".");

  var fn = (window || this);
  for (var i = 0, len = arr.length; i < len; i++) {
    fn = fn[arr[i]];
  }

  if (typeof fn !== "function") {
    throw new Error("function not found");
  }

  return  fn;
};

Example:

my = {};
my.namespaced = {};
(my.namespaced.MyClass = function() {
  console.log("constructed");
}).prototype = {
  do: function() {
    console.log("doing");
  }
};

var MyClass = stringToFunction("my.namespaced.MyClass");
var instance = new MyClass();
instance.do();
function myClass(arg){
}

var str="myClass";
dynamic_class=eval(str);

var instance=new dynamic_class(arg); // OK

Edit: inline example

function Person(name){
    this.name=name;
}
var person1=new (eval("Person"))("joe");

Browser global object is window and whenever you define global variables with var or functions with function, you are adding them in window. Thus you can get your "class" definition there:

var args = [];
var className = 'MyClass';
var obj = new window[className](args);

But this won't work for ES6 class declarations

Classes declared using ES6 keyword class are per-standard treated differently.

A class declared with class MyClass { } defines a global class that does not become a property of window global object. In other words the following applies

class MyClass {};
typeof window.MyClass === 'undefined';

So, how to do the same with ES6 classes? Object access notation is required because is what is needed to parse the string name, but parent object to search in is no longer available.

One way is to create your own context object, declare there your class and search for it there. In code:

// this variable actually goes in `window`
var classes = {};
// declare class inside
classes.MyClass = class {
   // the class code
};

var args = [];
var className = 'MyClass';
var obj = new classes[className](args); // dynamic for "new classes.MyClass(args)"

On Firefox, there are security rules for extensions, and so for the Javascript console. Don't make the mistake I did to test in the console because none of those solutions work. Whereas when you test from a page it works better :

  • the eval solution works well
  • Function('return new '... works (object is created) except for the constructor's arguments that are passed as "undefined" I didn't test other solutions.

In my case I was preloading data from my server and attempting to load the preloaded data using classes (in particular, I am using vuex-orm). Instead of anything super fancy, I opted for a list of models that I expect, and mapped them to classes that I had already imported at the top of the file. Observe:

import Video from '@models/Video'
import Purchase from '@models/Purchase'

let modelClassMap = {
    'Video': Video,
    'Purchase': Purchase,
}

Object.entries(preload.models).forEach(entry => {
    const [modelName, modelData] = entry
    if(modelClassMap[modelName]){
        modelClassMap[modelName].insertOrUpdate({data: modelData})
    }
})

Explicit, secure, simple. Nice!

Related