Create an Instance of a Class in Es6 with a Dynamic Name

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



Leave a reply



Submit