我有多个类似的课程,我想根据情况调用。我有一个变量,它将包含我想要调用的类的名称。
例如,我有这个JavaScript代码定义我的类。
class Parent {
constructor(id) {
// Do stuff...
}
}
class Child1 extends Parent {};
class Child2 extends Parent {}; // and many, many more...
然后我有了这个代码,它创建了一个新的Child1对象。
var obj = new Child1(id);
但是,我希望能够在变量中调用类的名称,然后用它调用它,如下所示:
var className = "Child1"; //Or child 2, depending on scenario.
var obj = new className(id);
我知道在PHP中我可以$obj = new $className(id);
,这正是我想用JavaScript做的。
我已经阅读了一些问题的答案(例如this one),表示我可以这样做:
var obj = new window[className](id);
但这样做会返回此错误:
Uncaught TypeError: window[className] is not a constructor
最初我在一个函数中定义了var className = "Child1"
,我认为问题是className
不是全局的,但当我尝试在全局定义className
时,它仍然没有工作......
答案 0 :(得分:1)
class
es不会成为全局对象的属性,因此window[...]
将不起作用。
您必须构建自己的映射:
// Can also use `Map` instead
const classes = {
Child1: Child1,
// or [Child1.name]: Child1 which can be useful if you want to build this dynamically
};
然后通过
查看课程classes[className]
答案 1 :(得分:1)
如果你想让它保持简洁,你需要利用eval
的邪恶力量,这样你的代码无论是否被调用都会有效在全球范围内与否:
class ClassA {}
class ClassB {}
const classToInstantiate = 'ClassB';
const myInstance = eval(`new ${classToInstantiate}()`);
console.log(myInstance instanceof ClassB);

虽然不得不诉诸这种技巧,但最终会产生代码异味,如果字符串变量的值以任何方式依赖于用户输入,则可能存在巨大的安全问题。
映射选项是您最有可能想要做的事情,即使它添加了一些样板,它更可靠,您可以更轻松地处理字符串不包含的情况有效的类名,例如:
class ClassA {}
class ClassB {}
const classNamesMap = {
ClassA,
ClassB,
};
function getClass(className) {
if (!className in classNamesMap) {
console.error('Invalid class name');
return null;
}
return classNamesMap[className];
}
const myInstance = new (getClass('ClassB'))();
console.log(myInstance instanceof ClassB);