如何在 JavaScript 中从字符串实例化一个类

Posted

技术标签:

【中文标题】如何在 JavaScript 中从字符串实例化一个类【英文标题】:How to instantiate a Class from a String in JavaScript 【发布时间】:2018-08-09 02:15:49 【问题描述】:

我处于一个奇怪的情况,我需要使用存储在变量中的字符串来实例化一个新类,但即使我确定类名是正确的,我也会收到一个错误,即给定的类名不是构造函数

这是一个无效的伪代码:

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

这会引发这个错误:

Uncaught TypeError: window[foo] is not a constructor

【问题讨论】:

window.Foo = class ... 而不是 class Foo ... 您可能需要使用eval() ***.com/questions/31776949/… 【参考方案1】:

一种可能性是使用eval

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

您必须评估在您的特定情况下使用eval() 的安全性。如果您知道要插入到运行 eval() 的代码中的字符串的来源,或者您可以先对其进行清理,那么它可能是安全的。


我个人更喜欢查找表。如果您有已知数量的要按字符串映射的类,那么您可以制作自己的查找表并使用它。这样做的好处是,如果字符串中有奇怪的东西,就不会产生意想不到的后果:

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);

如果你真的要走这条路,你可能想把它封装在一个函数中,然后在dict中找不到字符串时添加错误处理。

这应该比使用全局或Window 对象作为您的查找机制更好,原因如下:

    如果我记得,ES6 中的class 定义不会像其他***变量声明那样自动放在全局对象上(javascript 试图避免在先前的设计错误之上添加更多垃圾)。

    因此,如果您要手动分配给查找对象,您不妨使用不同的对象而不污染全局对象。这就是dict 对象在这里的用途。

【讨论】:

第二个选项的问题在于Open for Extension Close for Modification 原则。但我想至少这样改变的地方减少了 2.【参考方案2】:

类似于@jfriend00 ...

let className = "Foo";

let dynamicConstructor = ;
dynamicConstructor[className] = class 
    constructor()
        console.log('Foo!');
    
;

let fooInstance = new dynamicConstructor[className]();
console.debug(fooInstance);

也可以使用一种工厂类构造函数

const classFactory = (_className)=>
    let dynamicConstructor = ;
    dynamicConstructor[_className] = class 
        constructor(_code)
            this.code = _code;
            console.log(`$_className initialised with code: $_code!`);

        
    ;
    return dynamicConstructor[_className];


const MyClass = classFactory("Foo");
let fooInstance2 = new MyClass(123);

console.debug(fooInstance2);

【讨论】:

以上是关于如何在 JavaScript 中从字符串实例化一个类的主要内容,如果未能解决你的问题,请参考以下文章

在swift 3中从字符串实例化领域对象

在 Swift 5.0 中从 AppDelegate 实例化窗口失败 [重复]

在Java中从该类的主体内部实例化对象

如何在 JavaScript 中从末尾切分字符串? [复制]

如何在 init 方法中从 NIB 加载 IBOutlets?

如何在javascript中从字符串创建日期对象[重复]