【问题标题】:Get constructor by name in JS with Webpack and Babel使用 Webpack 和 Babel 在 JS 中按名称获取构造函数
【发布时间】:2021-05-27 22:15:03
【问题描述】:

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

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

我的班级在 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"),但没有成功,它返回window 对象。

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

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

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

【问题讨论】:

  • 你这样做的目的是什么?
  • 动态解析特定原型下的 JSON 对象。
  • 那句话没有意义。 “未解析”是什么意思?
  • “解析”我的错。是的,我知道 JSON 是什么,我正在合成...我想要的是从一个 JSON 字符串开始,并以一个特定类的对象结束。整个动态,使用type 属性、Object.assign 和其他东西。
  • @FlorentDescroix 啊,这更有意义。 :-)

标签: javascript typescript webpack babeljs vue-cli


【解决方案1】:

问题是我找不到合适的 SCOPE。

根据您的描述,没有。尽管 JavaScript 引擎会记录您模块中的每次导入,但您的代码无法访问该记录列表。

如果你想这样做,你需要将你想使用的对象/构造函数放入一个对象或自己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]();

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


但是,你说过:

我想做的是:

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

如果您有该类的实例,则没有理由使用这样的名称,只需使用foo.constructor

class World {
}


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

在您提出的评论中:

有没有办法让我的类定义在任何地方都可以访问(就像没有导出的方式一样)?至少对控制台中的调试很有用。

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

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

【讨论】:

  • 我实际上是在合成我的代码以给出我正在寻找的东西的想法。显然,如果就这么简单,我会有任何问题^^
  • 感谢您对出口的澄清,我现在更好理解了。有没有办法让我的类定义在任何地方都可以访问(就像没有导出的方式一样)?至少它对控制台中的调试很有用。
  • @FlorentDescroix - 你可以维护一个注册表。我已经添加到答案中。编码愉快!
猜你喜欢
  • 1970-01-01
  • 2013-01-12
  • 2015-06-23
  • 1970-01-01
  • 2018-02-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多