使用 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();
我目前正在使用 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();