Create an instance of a class in ES6 with a dynamic name?
There are a few ways you can accomplish this...
1. Proxy Class
Following from @thefourtheye's example of maintaining a mapping of name to class, you could have a class whose job is to take the name of the desired class and proxy its instantiation:
[ See it working ]
Define your classes
// ClassOne.js
export class ClassOne {
constructor () {
console.log("Hi from ClassOne");
}
}
// ClassTwo.js
export class ClassTwo {
constructor (msg) {
console.log(`${msg} from ClassTwo`);
}
}
Define the proxy class (e.g. DynamicClass
)
import ClassOne from './ClassOne';
import ClassTwo from './ClassTwo';
// Use ES6 Object Literal Property Value Shorthand to maintain a map
// where the keys share the same names as the classes themselves
const classes = {
ClassOne,
ClassTwo
};
class DynamicClass {
constructor (className, opts) {
return new classes[className](opts);
}
}
export default DynamicClass;
Example usage
import DynamicClass from './DynamicClass';
new DynamicClass('ClassOne'); //=> "Hi from ClassOne"
new DynamicClass('ClassTwo', 'Bye'); //=> "Bye from ClassTwo"
2. Factory Function
Use a function that performs a lookup against an object of class name -> class mappings and returns reference to the class, which we can then instantiate as usual.
Define the factory function
import ClassOne from './ClassOne';
import ClassTwo from './ClassTwo';
const classes = { ClassOne, ClassTwo };
export default function dynamicClass (name) {
return classes[name];
}
Example usage
import dynamicClass from './dynamicClass'
const ClassOne = dynamicClass('ClassOne') // Get the ClassOne class
new ClassOne(args) // Create an instance of ClassOne
Dynamically init an instance with ES6 JavaScript class
The usual way to do this is to put your constructors on an object, and then look them up on that object using the generated string key:
let ctors = {
AnObject: class {
constructor(name) {
this.name = name;
}
}
};
let className = "An" + "Object";
let p2 = new ctors[className]("name2");
console.log("p2 name: " + p2.name);
Live copy on Babel's REPL
Alternately, and I'm just being complete here not recommending it, you can use eval
:
class AnObject {
constructor(name) {
this.name = name;
}
}
let className = "An" + "Object";
let p2 = new (eval(className))("name2");
console.log("p2 name: " + p2.name)
Live copy on Babel's REPL
Or a bit more verbose, but possibly clearer:
let className = "An" + "Object";
let ctor = eval(className);
let p2 = new ctor("name2");
console.log("p2 name: " + p2.name)
eval
is fine as long as you're in complete control of the strings you're evaluating. But it's usually overkill in well-structured code.
ES6 Dynamic class names
There is probably a better solution for whatever you are trying to achieve, but you can assign a class expression to an object:
let classes = {};
classes[someName] = class { ... };
This didn't really change in ES2015: if you want to create a dynamically named binding, you have to use an object or some other mapping instead.
javascript: dynamically create class instances
You need to have a name-class mapping somewhere. Factory function or somewhere else is your call. Your current solution lacks this, which is causing the problem:
...creates a new, empty Header class and, I suppose, it's instance. It is not the Header class that I have already written and want to create an instance for
Some explanation with a simple example
// Imagine you've defined Testclass Test { callMe() {}}
// And your consumer wants a className Test to be createdconst className = "Test";
// This is a simple map of the name to classconst nameToClass = { "Test": Test}
// This creates a new class called Test, not your defined classconst AttemptedDynamicTest = new Function(` return class ${className} {} `)();
// The next two logs just prove the previous commentconsole.log(Test === AttemptedDynamicTest); // falseconsole.log(typeof AttemptedDynamicTest.prototype.callMe); // undefined
// What you really need is to maintain a map, and just use it to dynamically// create a new instance every timeconsole.log(typeof nameToClass[className].prototype.callMe); // function
JavaScript - Dynamically loading a class and creating new instance with specific properties
The second argument to Object.create
is the same argument you would pass to Object.defineProperties
, your properties
is therefore invalid. Instead use Object.assign:
Object.assign(Object.create(Animal.prototype), properties)
But why don't you just call the constructor?
new Animal(properties)
Secondly this:
properties = properties || {};
is probably intended to be:
this.properties = properties || {};
And I wouldn't recommend to dynamically require
, especially not from a user entered value, instead create a lookup object:
const AnimalByName = {
Bear: require("./Bear"),
//...
};
const instance = new AnimalByName[name](properties);
Is it possible to instantiate a javascript class from a dynamic variable?
If you do..
import components from './components';
components
will now be an object containing a property for each export
within the components.js
file.
So you can either do..
var c1 = components.ComponentOne // or...
var c1 = components['ComponentOne']
So you can do this: (from your example)
import components from './components';
function addComponentToEntity(componentId, entityId) {
//componentId is the name of the Class that needs to be instantiated
let comp = new components[componentId];
//Do stuff with the newly instantiated class and add it to the entity
}
Create object from class name in JavasScript ECMAScript 6
Don't put class names on that object. Put the classes themselves there, so that you don't have to rely on them being global and accessible (in browsers) through window
.
Btw, there's no good reason to make this factory a class, you would probably only instantiate it once (singleton). Just make it an object:
export class Column {}
export class Sequence {}
export class Checkbox {}
export const columnFactory = {
specColumn: {
__default: Column, // <--
__sequence: Sequence, // <--
__checkbox: Checkbox // <--
},
create(name, ...args) {
let cls = this.specColumn[name] || this.specColumn.__default;
return new cls(...args);
}
};
Related Topics
Inspect Attached Event Handlers for Any Dom Element
Getting Error "Form Submission Canceled Because the Form Is Not Connected"
How to Access a Child's State in React
Plain Count Up Timer in JavaScript
Is It Safe to Assume Strict Comparison in a JavaScript Switch Statement
How to Define Setter/Getter on Prototype
Detect iPad Users Using Jquery
How to Implement Prepend and Append with Regular JavaScript
Setting Multiple Attributes for an Element at Once with JavaScript
How to Animate Scrolltop with Jquery
JavaScript - Return String Between Square Brackets
JavaScript - Difference Between Array and Array-Like Object
Handle Url Fragment Identifier (Anchor) Change Event in JavaScript
How to Access Component Methods from "Outside" in Reactjs