使用 Webpack 和 Babel 在 JS 中按名称获取构造函数

Get constructor by name in JS with Webpack and Babel

我目前正在使用 Webpack 和 Babel 开发一个项目。更具体地说,我使用 vue-cli 框架,但这无关紧要。

我想从它的字符串名称中获取一个构造函数。

我的 class 是在 World.ts 文件中设置的:

export default class World { ... }

并在另一个文件中这样使用:

import World from "./World";

我想做的是:

let foo = new World();
let className = foo.constructor.name;
let bar = new SCOPE[className]();

问题是我没有找到合适的 SCOPE。
我试过了 window[className] 没用。
我试过了eval('let bar = new ${className}()'),也没用。
我已经尝试 const SCOPE = (0, eval)("this") 在我的进口之下,但没有成功,它 returns window 对象。

到目前为止,我找到的唯一解决方案是根据我的构造函数的名称创建一个 Map,但这根本不是动态的。

const classesByName = new Map<string, any>([
  [World.name, World],
  ...
]);

所以...我猜 Webpack 或 Babel 正在某处做某事。
我该怎么办?

The issue is that I don't find the right SCOPE.

根据您的描述,没有。虽然 JavaScript 引擎将记录您模块中的每个导入,但您的代码无法访问该记录列表。

如果你想这样做,你需要把你想用的 objects/constructors 放在一个对象中或 Map 你自己,然后从那里使用它们。

如果你有那些不同的构造函数作为模块中的命名导出,就像这样:

export class World { /* ... */ }
export class Universe { /* ... */ }
export class Multiverse { /* ... */ }

...那么您可以为模块使用模块名称空间对象,如下所示:

import * as constructors from "./your-module.js";

const name = /*...get the name of one of the constructors dynamically...*/;
const newInstance = new constructors[name]();

当然,许多构造函数都希望接收参数。


但是,你说:

What I'd like to do is :

let foo = new World();
let className = foo.constructor.name;
let bar = new SCOPE[className]();

如果您有 class 的实例,则没有理由像这样遍历名称,只需使用 foo.constructor:

class World {
}


let foo = new World();
let bar = new foo.constructor();
console.log(bar instanceof World); // true


在您提出的评论中:

Is there any way to have my Class definitions accessible anywhere then (the way it would be without export) ? At least it would be quite useful for the debug in the console.

我想到的是您可以拥有一个 class 注册表并让导出 classes 的模块使用该注册表。例如:

registry.js:

const registry = new Map();
export function registerClass(cls) {
    registry.set(cls.name, cls);
    return cls;
}
export function getClass(name) {
    return registry.get(name);
}

然后在 World.js:

import { registerClass } from "./registry.js";
export default registerClass(class World {
    // ...
});

或者如果使用命名导出:

import { registerClass } from "./registry.js";
export class World {
    // ...
}
registerClass(World);

当你想使用名字中的一个时:

import { getClass } from "./registry.js";
const Ctor = getClass(name);
const obj = new Ctor();