Can You Implement Javascript Class Via Function Expression? - javascript

I was tackling this question in leet code:
Implement the MapSum class:
MapSum() Initializes the MapSum object. void insert(String key, int
val) Inserts the key-val pair into the map. If the key already
existed, the original key-value pair will be overridden to the new
one. int sum(string prefix) Returns the sum of all the pairs' value
whose key starts with the prefix.
In javascript, the template for solving the question is:
/**
* Initialize your data structure here.
*/
var MapSum = function() {
};
/**
* #param {string} key
* #param {number} val
* #return {void}
*/
MapSum.prototype.insert = function(key, val) {
};
/**
* #param {string} prefix
* #return {number}
*/
MapSum.prototype.sum = function(prefix) {
};
/**
* Your MapSum object will be instantiated and called as such:
* var obj = new MapSum()
* obj.insert(key,val)
* var param_2 = obj.sum(prefix)
*/
I was struck by the class template. I'm used to seeing javascript classes more similar to this:
class MapSum {
constructor() {
}
insert(key, value) {
}
sum(prefix) {
}
}
Is the template leetcode provided, considered a class? What kind of class is it? What is it called when you initialize an object via function expression (var MapSum = function() { //....}) ? What are the biggest differences/implications from writing a class that way vs the way I suggested?

The class keyword is actually just syntaxic sugar over prototypal inheritance
This code demonstrates that the two syntaxes are equivalent:
class MapSum {
constructor() {
}
insert(key, value) {
}
sum(prefix) {
}
}
console.log(typeof MapSum); // function (actually the constructor)
console.log(MapSum.prototype.insert); // function
console.log(MapSum.prototype.sum); // function
A class is actually just a constructor function, which has a special object named prototype attached to it. Every instance of the class has an internal link to the prototype of the constructor.

Related

How to turn a string into class in typescript? [duplicate]

I want create object factory using ES6 but old-style syntax doesn't work with new.
I have next code:
export class Column {}
export class Sequence {}
export class Checkbox {}
export class ColumnFactory {
constructor() {
this.specColumn = {
__default: 'Column',
__sequence: 'Sequence',
__checkbox: 'Checkbox'
};
}
create(name) {
let className = this.specColumn[name] ? this.specColumn[name] : this.specColumn['__default'];
return new window[className](name); // this line throw error
}
}
let factory = new ColumnFactory();
let column = factory.create('userName');
What do I do wrong?
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);
}
};
There is a small & dirty way to do that:
function createClassByName(name,...a) {
var c = eval(name);
return new c(...a);
}
You can now create a class like that:
let c = createClassByName( 'Person', x, y );
The problem is that the classes are not properties of the window object. You can have an object with properties "pointing" to your classes instead:
class Column {}
class Sequence {}
class Checkbox {}
let classes = {
Column,
Sequence,
Checkbox
}
class ColumnFactory {
constructor() {
this.specColumn = {
__default: 'Column',
__sequence: 'Sequence',
__checkbox: 'Checkbox'
};
}
create(name) {
let className = this.specColumn[name] ? this.specColumn[name] : this.specColumn['__default'];
return new classes[className](name); // this line no longer throw error
}
}
let factory = new ColumnFactory();
let column = factory.create('userName');
export {ColumnFactory, Column, Sequence, Checkbox};
For those of you that are not using ES6 and want to know how you can create classes by using a string here is what I have done to get this to work.
"use strict";
class Person {
constructor(x, y) {
this.x = x;
this.y = y;
}
}
window.classes = {};
window.classes.Person = Person;
document.body.innerText = JSON.stringify(new window.classes["Person"](1, 2));
As you can see the easiest way to do this is to add the class to an object.
Here is the fiddle:
https://jsfiddle.net/zxg7dsng/1/
Here is an example project that uses this approach:
https://github.com/pdxjohnny/dist-rts-client-web
I prefer this method:
allThemClasses.js
export class A {}
export class B {}
export class C {}
script.js
import * as Classes from './allThemClasses';
const a = new Classes['A'];
const b = new Classes['B'];
const c = new Classes['C'];
I know this is an old post, but recently I've had the same question about how to instance a class dynamically
I'm using webpack so following the documentation there is a way to load a module dynamically using the import() function
js/classes/MyClass.js
class MyClass {
test = null;
constructor(param) {
console.log(param)
this.test = param;
}
}
js/app.js
var p = "example";
var className = "MyClass";
import('./classes/'+className).then(function(mod) {
let myClass = new mod[className](p);
console.log(myClass);
}, function(failMsg) {
console.error("Fail to load class"+className);
console.error(failMsg);
});
Beware: this method is asynchronous and I can't really tell the performance cost for it,
But it works perfectly on my simple program (worth a try ^^)
Ps: To be fare I'm new to Es6 (a couple of days) I'm more a C++ / PHP / Java developer.
I hope this helps anyone that come across this question and that is it not a bad practice ^^".
Clarification
There are similar questions to this, including this SO question that was closed, that are looking for proxy classes or factory functions in JavaScript; also called dynamic classes. This answer is a modern solution in case you landed on this answer looking for any of those things.
Answer / Solution
As of 2022 I think there is a more elegant solution for use in the browser. I made a class called Classes that self-registers the property Class (uppercase C) on the window; code below examples.
Now you can have classes that you want to be able to reference dynamically register themselves globally:
// Make a class:
class Handler {
handleIt() {
// Handling it...
}
}
// Have it register itself globally:
Class.add(Handler);
// OR if you want to be a little more clear:
window.Class.add(Handler);
Then later on in your code all you need is the name of the class you would like to get its original reference:
// Get class
const handler = Class.get('Handler');
// Instantiate class for use
const muscleMan = new (handler)();
Or, even easier, just instantiate it right away:
// Directly instantiate class for use
const muscleMan = Class.new('Handler', ...args);
Code
You can see the latest code on my gist. Add this script before all other scripts and all of your classes will be able to register with it.
/**
* Adds a global constant class that ES6 classes can register themselves with.
* This is useful for referencing dynamically named classes and instances
* where you may need to instantiate different extended classes.
*
* NOTE: This script should be called as soon as possible, preferably before all
* other scripts on a page.
*
* #class Classes
*/
class Classes {
#classes = {};
constructor() {
/**
* JavaScript Class' natively return themselves, we can take advantage
* of this to prevent duplicate setup calls from overwriting the global
* reference to this class.
*
* We need to do this since we are explicitly trying to keep a global
* reference on window. If we did not do this a developer could accidentally
* assign to window.Class again overwriting any classes previously registered.
*/
if (window.Class) {
// eslint-disable-next-line no-constructor-return
return window.Class;
}
// eslint-disable-next-line no-constructor-return
return this;
}
/**
* Add a class to the global constant.
*
* #method
* #param {Class} ref The class to add.
* #return {boolean} True if ths class was successfully registered.
*/
add(ref) {
if (typeof ref !== 'function') {
return false;
}
this.#classes[ref.prototype.constructor.name] = ref;
return true;
}
/**
* Checks if a class exists by name.
*
* #method
* #param {string} name The name of the class you would like to check.
* #return {boolean} True if this class exists, false otherwise.
*/
exists(name) {
if (this.#classes[name]) {
return true;
}
return false;
}
/**
* Retrieve a class by name.
*
* #method
* #param {string} name The name of the class you would like to retrieve.
* #return {Class|undefined} The class asked for or undefined if it was not found.
*/
get(name) {
return this.#classes[name];
}
/**
* Instantiate a new instance of a class by reference or name.
*
* #method
* #param {Class|name} name A reference to the class or the classes name.
* #param {...any} args Any arguments to pass to the classes constructor.
* #returns A new instance of the class otherwise an error is thrown.
* #throws {ReferenceError} If the class is not defined.
*/
new(name, ...args) {
// In case the dev passed the actual class reference.
if (typeof name === 'function') {
// eslint-disable-next-line new-cap
return new (name)(...args);
}
if (this.exists(name)) {
return new (this.#classes[name])(...args);
}
throw new ReferenceError(`${name} is not defined`);
}
/**
* An alias for the add method.
*
* #method
* #alias Classes.add
*/
register(ref) {
return this.add(ref);
}
}
/**
* Insure that Classes is available in the global scope as Class so other classes
* that wish to take advantage of Classes can rely on it being present.
*
* NOTE: This does not violate https://www.w3schools.com/js/js_reserved.asp
*/
const Class = new Classes();
window.Class = Class;
This is an old question but we can find three main approaches that are very clever and useful:
1. The Ugly
We can use eval to instantiate our class like this:
class Column {
constructor(c) {
this.c = c
console.log(`Column with ${this.c}`);
}
}
function instantiator(name, ...params) {
const c = eval(name)
return new c(...params)
}
const name = 'Column';
const column = instantiator(name, 'box')
console.log({column})
However, eval has a big caveat, if we don't sanitize and don't add some layers of security, then we will have a big security whole that can be expose.
2. The Good
If we know the class names that we will use, then we can create a lookup table like this:
class Column {
constructor(c) {
console.log(`Column with ${c}`)
}
}
class Sequence {
constructor(a, b) {
console.log(`Sequence with ${a} and ${b}`)
}
}
class Checkbox {
constructor(c) {
console.log(`Checkbox with ${c}`)
}
}
// construct dict object that contains our mapping between strings and classes
const classMap = new Map([
['Column', Column],
['Sequence', Sequence],
['Checkbox', Checkbox],
])
function instantiator(name, ...p) {
return new(classMap.get(name))(...p)
}
// make a class from a string
let object = instantiator('Column', 'box')
object = instantiator('Sequence', 'box', 'index')
object = instantiator('Checkbox', 'box')
3. The Pattern
Finally, we can just create a Factory class that will safety handle the allowed classes and throw an error if it can load it.
class Column {
constructor(c) {
console.log(`Column with ${c}`)
}
}
class Sequence {
constructor(a, b) {
console.log(`Sequence with ${a} and ${b}`)
}
}
class Checkbox {
constructor(c) {
console.log(`Checkbox with ${c}`)
}
}
class ClassFactory {
static class(name) {
switch (name) {
case 'Column':
return Column
case 'Sequence':
return Sequence
case 'Checkbox':
return Checkbox
default:
throw new Error(`Could not instantiate ${name}`);
}
}
static create(name, ...p) {
return new(ClassFactory.class(name))(...p)
}
}
// make a class from a string
let object
object = ClassFactory.create('Column', 'box')
object = ClassFactory.create('Sequence', 'box', 'index')
object = ClassFactory.create('Checkbox', 'box')
I recommend The Good method. It is is clean and safe. Also, it should be better than using global or window object:
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).
Therefore we will not pollute the global object because we are using a local classMap object to lookup the required class.

How to define a static variable inside a JS class

I'm building a static class to store data inside an a array and i want to declare a static variable but i don't know how to do it on javascript.
JS code:
class GCache {
// Define cache variable
static cache = {}; // <--- that is what i don't know how to do
/**
* Check if data is on cache
* #param {*} id
*/
static isOnCache(id){
return this.cache.hasOwnProperty(id);
}
/**
* Add data to cache
* #param {*} id
* #param {*} json
*/
static addToCache(id, json){
if(this.isOnCache(id)) return;
this.cache[id] = json;
}
/**
* Obtain data from cache
* #param {*} id
*/
static getFromCache(id){
if(this.isOnCache(id)) return;
return this.cache[id];
}
}
Thank you <3
In up-to-date JavaScript environments, you can use the static keyword when inside a class to assign properties to the instance itself - the code in your question works fine now.
class SomeClass {
static someStaticProperty = {}
}
console.log(SomeClass.someStaticProperty);
In older environments, and at the time the question was originally posted, non-function properties couldn't be added to a class itself inside the class definition. It looks ugly, but you'll have to assign the property outside of the class definition:
class GCache {
...
}
GCache.cache = {};
Also note that your getFromCache function probably has a bug: you probably want to return early if the id being searched for does not exist in the cache:
if(!this.isOnCache(id)) return;
class GCache {
/**
* Check if data is on cache
* #param {*} id
*/
static isOnCache(id){
return this.cache.hasOwnProperty(id);
}
/**
* Add data to cache
* #param {*} id
* #param {*} json
*/
static addToCache(id, json){
if(this.isOnCache(id)) return;
this.cache[id] = json;
}
/**
* Obtain data from cache
* #param {*} id
*/
static getFromCache(id){
if(!this.isOnCache(id)) return;
return this.cache[id];
}
}
GCache.cache = {};
GCache.addToCache('myid', 'data');
console.log(GCache.getFromCache('myid'));
But, in this case, it would probably be easier to use a plain object, rather than a class. The class isn't being used to instantiate anything, after all, and with an object, you can both define cache inside the object, and reduce the syntax noise by getting rid of all the statics:
const GCache = {
cache: {},
isOnCache(id) {
return this.cache.hasOwnProperty(id);
},
addToCache(id, json) {
if (this.isOnCache(id)) return;
this.cache[id] = json;
},
getFromCache(id) {
if (!this.isOnCache(id)) return;
return this.cache[id];
}
}
GCache.addToCache('myid', 'data');
console.log(GCache.getFromCache('myid'));
There is currently a proposal allowing you to set static non-method properties onto a class. It's currently at Stage 2, which means it's expected to eventually be implemented officially. Once it lands, the code:
class GCache {
...
}
GCache.cache = {};
can be replaced by:
class GCache {
static cache = {};
...
}
If you mean static variable for all instance of the class,
declare:
GCache.cache = {}
below your class declaration
Babel's plugin-proposal-class-properties is probably what you're looking for. It enables support for static variables/methods inside the class declaration.

JSDocs - How to document implicit parameters and returns

I am wondering how to document a function like the following:
var createInput = function () {
var type = this.type;
this.input = {
val: {},
type: type
};
}
Technically this.type is an input parameter and this.input is what is returned from this object. How would one document this?
Riffing on the second link by sapithpocker seems to show a potential solution.
/**
* The context of the current class.
* #typedef {Object} ClassContext.
* #property {string} type - Indicates type. */
/**
* A method for doing something.
* #param {...ClassContext} this - a {#link ClassContext} object.
*/
function createInput() { /* Code */ }
This is documentation that can be reused for each method the uses object that "owns" the current context, i.e. this, and follows the DRY-principle, as well.
It is better to rewrite the code someway so that it takes arguments and returns some value without any side effects. Easy to document as well!
The question should be more like how to avoid side-effects, rather than how to document side effects.
var createInput = function (type) {
return {
val: {},
type: type
};
}
this.input = createInput(this.type);

How can I document a 'this' instance inside a callback function in WebStorm?

Having this code:
function Element() {
this.name = "yay";
}
Element.prototype.extend = function(object) {
if (object instanceof Object) {
for (var n in object) {
if (object.hasOwnProperty(n)) {
this[n] = object[n];
}
}
}
};
var el = new Element();
el.extend({
update: function() {
console.log(this.name);
}
});
I want WebStorm to know that update() this is an instance of Element, but I don't really know how to do it.
The maximum I've reached is this:
el.extend({
/**
* #this Element
*/
update: function() {
console.log(this.name);
}
});
But I don't want to do that in every extend().
Also found this:
/**
* #typedef {Object} FunctionExtend
*/
/**
* #param {FunctionExtend} object
*/
Element.prototype.extend = function(object) {
[...]
But I'm stuck in:
How to declare FunctionExtend to have undefined number of parameters.
How to tell that each #parameter will be a callback without knowing the parameter name.
How to tell what is the #this of the callbacks.
Extending prototypes to begin with is generally a Bad Idea™, and it does not play well with write-time documentation tools like JSDoc.
You will probably have no choice but to document every function individually.

Create object from class name in JavasScript ECMAScript 6

I want create object factory using ES6 but old-style syntax doesn't work with new.
I have next code:
export class Column {}
export class Sequence {}
export class Checkbox {}
export class ColumnFactory {
constructor() {
this.specColumn = {
__default: 'Column',
__sequence: 'Sequence',
__checkbox: 'Checkbox'
};
}
create(name) {
let className = this.specColumn[name] ? this.specColumn[name] : this.specColumn['__default'];
return new window[className](name); // this line throw error
}
}
let factory = new ColumnFactory();
let column = factory.create('userName');
What do I do wrong?
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);
}
};
There is a small & dirty way to do that:
function createClassByName(name,...a) {
var c = eval(name);
return new c(...a);
}
You can now create a class like that:
let c = createClassByName( 'Person', x, y );
The problem is that the classes are not properties of the window object. You can have an object with properties "pointing" to your classes instead:
class Column {}
class Sequence {}
class Checkbox {}
let classes = {
Column,
Sequence,
Checkbox
}
class ColumnFactory {
constructor() {
this.specColumn = {
__default: 'Column',
__sequence: 'Sequence',
__checkbox: 'Checkbox'
};
}
create(name) {
let className = this.specColumn[name] ? this.specColumn[name] : this.specColumn['__default'];
return new classes[className](name); // this line no longer throw error
}
}
let factory = new ColumnFactory();
let column = factory.create('userName');
export {ColumnFactory, Column, Sequence, Checkbox};
For those of you that are not using ES6 and want to know how you can create classes by using a string here is what I have done to get this to work.
"use strict";
class Person {
constructor(x, y) {
this.x = x;
this.y = y;
}
}
window.classes = {};
window.classes.Person = Person;
document.body.innerText = JSON.stringify(new window.classes["Person"](1, 2));
As you can see the easiest way to do this is to add the class to an object.
Here is the fiddle:
https://jsfiddle.net/zxg7dsng/1/
Here is an example project that uses this approach:
https://github.com/pdxjohnny/dist-rts-client-web
I prefer this method:
allThemClasses.js
export class A {}
export class B {}
export class C {}
script.js
import * as Classes from './allThemClasses';
const a = new Classes['A'];
const b = new Classes['B'];
const c = new Classes['C'];
I know this is an old post, but recently I've had the same question about how to instance a class dynamically
I'm using webpack so following the documentation there is a way to load a module dynamically using the import() function
js/classes/MyClass.js
class MyClass {
test = null;
constructor(param) {
console.log(param)
this.test = param;
}
}
js/app.js
var p = "example";
var className = "MyClass";
import('./classes/'+className).then(function(mod) {
let myClass = new mod[className](p);
console.log(myClass);
}, function(failMsg) {
console.error("Fail to load class"+className);
console.error(failMsg);
});
Beware: this method is asynchronous and I can't really tell the performance cost for it,
But it works perfectly on my simple program (worth a try ^^)
Ps: To be fare I'm new to Es6 (a couple of days) I'm more a C++ / PHP / Java developer.
I hope this helps anyone that come across this question and that is it not a bad practice ^^".
Clarification
There are similar questions to this, including this SO question that was closed, that are looking for proxy classes or factory functions in JavaScript; also called dynamic classes. This answer is a modern solution in case you landed on this answer looking for any of those things.
Answer / Solution
As of 2022 I think there is a more elegant solution for use in the browser. I made a class called Classes that self-registers the property Class (uppercase C) on the window; code below examples.
Now you can have classes that you want to be able to reference dynamically register themselves globally:
// Make a class:
class Handler {
handleIt() {
// Handling it...
}
}
// Have it register itself globally:
Class.add(Handler);
// OR if you want to be a little more clear:
window.Class.add(Handler);
Then later on in your code all you need is the name of the class you would like to get its original reference:
// Get class
const handler = Class.get('Handler');
// Instantiate class for use
const muscleMan = new (handler)();
Or, even easier, just instantiate it right away:
// Directly instantiate class for use
const muscleMan = Class.new('Handler', ...args);
Code
You can see the latest code on my gist. Add this script before all other scripts and all of your classes will be able to register with it.
/**
* Adds a global constant class that ES6 classes can register themselves with.
* This is useful for referencing dynamically named classes and instances
* where you may need to instantiate different extended classes.
*
* NOTE: This script should be called as soon as possible, preferably before all
* other scripts on a page.
*
* #class Classes
*/
class Classes {
#classes = {};
constructor() {
/**
* JavaScript Class' natively return themselves, we can take advantage
* of this to prevent duplicate setup calls from overwriting the global
* reference to this class.
*
* We need to do this since we are explicitly trying to keep a global
* reference on window. If we did not do this a developer could accidentally
* assign to window.Class again overwriting any classes previously registered.
*/
if (window.Class) {
// eslint-disable-next-line no-constructor-return
return window.Class;
}
// eslint-disable-next-line no-constructor-return
return this;
}
/**
* Add a class to the global constant.
*
* #method
* #param {Class} ref The class to add.
* #return {boolean} True if ths class was successfully registered.
*/
add(ref) {
if (typeof ref !== 'function') {
return false;
}
this.#classes[ref.prototype.constructor.name] = ref;
return true;
}
/**
* Checks if a class exists by name.
*
* #method
* #param {string} name The name of the class you would like to check.
* #return {boolean} True if this class exists, false otherwise.
*/
exists(name) {
if (this.#classes[name]) {
return true;
}
return false;
}
/**
* Retrieve a class by name.
*
* #method
* #param {string} name The name of the class you would like to retrieve.
* #return {Class|undefined} The class asked for or undefined if it was not found.
*/
get(name) {
return this.#classes[name];
}
/**
* Instantiate a new instance of a class by reference or name.
*
* #method
* #param {Class|name} name A reference to the class or the classes name.
* #param {...any} args Any arguments to pass to the classes constructor.
* #returns A new instance of the class otherwise an error is thrown.
* #throws {ReferenceError} If the class is not defined.
*/
new(name, ...args) {
// In case the dev passed the actual class reference.
if (typeof name === 'function') {
// eslint-disable-next-line new-cap
return new (name)(...args);
}
if (this.exists(name)) {
return new (this.#classes[name])(...args);
}
throw new ReferenceError(`${name} is not defined`);
}
/**
* An alias for the add method.
*
* #method
* #alias Classes.add
*/
register(ref) {
return this.add(ref);
}
}
/**
* Insure that Classes is available in the global scope as Class so other classes
* that wish to take advantage of Classes can rely on it being present.
*
* NOTE: This does not violate https://www.w3schools.com/js/js_reserved.asp
*/
const Class = new Classes();
window.Class = Class;
This is an old question but we can find three main approaches that are very clever and useful:
1. The Ugly
We can use eval to instantiate our class like this:
class Column {
constructor(c) {
this.c = c
console.log(`Column with ${this.c}`);
}
}
function instantiator(name, ...params) {
const c = eval(name)
return new c(...params)
}
const name = 'Column';
const column = instantiator(name, 'box')
console.log({column})
However, eval has a big caveat, if we don't sanitize and don't add some layers of security, then we will have a big security whole that can be expose.
2. The Good
If we know the class names that we will use, then we can create a lookup table like this:
class Column {
constructor(c) {
console.log(`Column with ${c}`)
}
}
class Sequence {
constructor(a, b) {
console.log(`Sequence with ${a} and ${b}`)
}
}
class Checkbox {
constructor(c) {
console.log(`Checkbox with ${c}`)
}
}
// construct dict object that contains our mapping between strings and classes
const classMap = new Map([
['Column', Column],
['Sequence', Sequence],
['Checkbox', Checkbox],
])
function instantiator(name, ...p) {
return new(classMap.get(name))(...p)
}
// make a class from a string
let object = instantiator('Column', 'box')
object = instantiator('Sequence', 'box', 'index')
object = instantiator('Checkbox', 'box')
3. The Pattern
Finally, we can just create a Factory class that will safety handle the allowed classes and throw an error if it can load it.
class Column {
constructor(c) {
console.log(`Column with ${c}`)
}
}
class Sequence {
constructor(a, b) {
console.log(`Sequence with ${a} and ${b}`)
}
}
class Checkbox {
constructor(c) {
console.log(`Checkbox with ${c}`)
}
}
class ClassFactory {
static class(name) {
switch (name) {
case 'Column':
return Column
case 'Sequence':
return Sequence
case 'Checkbox':
return Checkbox
default:
throw new Error(`Could not instantiate ${name}`);
}
}
static create(name, ...p) {
return new(ClassFactory.class(name))(...p)
}
}
// make a class from a string
let object
object = ClassFactory.create('Column', 'box')
object = ClassFactory.create('Sequence', 'box', 'index')
object = ClassFactory.create('Checkbox', 'box')
I recommend The Good method. It is is clean and safe. Also, it should be better than using global or window object:
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).
Therefore we will not pollute the global object because we are using a local classMap object to lookup the required class.

Categories