【问题标题】:How to instantiate a Class from a String in JavaScript如何在 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

【问题讨论】:

标签: javascript es6-class


【解决方案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 对象作为您的查找机制更好,原因如下:

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

  2. 因此,如果您要手动分配给查找对象,您不妨使用不同的对象而不污染全局对象。这就是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);

【讨论】:

    猜你喜欢
    • 2012-12-23
    • 2020-12-15
    • 1970-01-01
    • 2011-10-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-01-14
    相关资源
    最近更新 更多