我正在根据从数据库中提取的描述性数据动态构建类。例如,如果数据如下:
ClassName = ExampleParent
Method1.name = "greet"
Method1.code = "console.log(\"Parent hello\");"
并像这样构建它可以正常工作:
classList[ClassName] = function(){}
classList[ClassName].prototype[Method1.name] = Function(Method1.code);
var Bob = new classList["ExampleParent"]();
Bob.greet();
但我对如何动态创建继承感到难过:
ClassName = ExampleChild
ClassExtends = ExampleParent
Method1.name = "greet"
Method1.code = "super.greet(); console.log(\"Child hello\");"
我不知道如何使用 ExampleChild.prototype 指向ExampleParent并包含ExampleChild的自定义方法,即使我尝试过,它也说 super 不明。我不需要支持任何花哨的东西(私有,静态等)...我只需要这个和 super 来工作。提示?
答案 0 :(得分:0)
不幸的是,您不能不使用eval
(或通过让eval
返回执行该功能的函数来有效地使用Function
),但这仍然与您所做的一致像Function
一样,eval
允许执行任意代码。不过,这很难看。
您绝对信任数据来源非常重要。因为eval
(和Function
)允许执行任意代码,所以您不得(例如)允许用户A编写将存储在数据库中的代码,供用户B在没有绝对信任用户A的情况下进行检索和使用。它会使用户B面临风险,可能会将他们暴露给用户A的恶意代码。 / p>
有了这个警告,您可以使用eval
,例如:
const className = "ExampleChild";
const parentName = "ExampleParent";
const methodName = "greet";
const methodCode = "super.greet();";
const C = eval(`
class ${className} extends ${parentName} {
${methodName}() {
${methodCode}
}
}`
);
您可能需要一个对象来按运行时名称存储类,因为这就是extends
子句所需要的。
示例:
const classes = {};
function buildClass(spec) {
const extendsClause = spec.parentName ? ` extends classes.${spec.parentName}` : "";
const methods = spec.methods.map(
mspec => `${mspec.name}() { ${mspec.code} }`
).join("\n");
const cls = classes[spec.className] = eval(`
class ${spec.className} ${extendsClause} {
${methods}
}`
);
return cls;
}
const specs = [
{
className: "ExampleParent",
methods: [
{name: "greet", code: "console.log(\"Parent hello\");"}
]
},
{
className: "ExampleChild",
parentName: "ExampleParent",
methods: [
{name: "greet", code: "super.greet(); console.log(\"Child hello\");"}
]
}
];
specs.forEach(buildClass);
let c = new classes.ExampleChild();
c.greet();
答案 1 :(得分:-1)
您可以在子类原型中创建一个名为super
的属性,并使用超类的实例进行设置。
看一下这个例子:
// -- Base Structure - This code is fixed, hard coded --
var classList = {};
// Register a new class
function registerClass(definition) {
var cls, i, method;
cls = function() {};
if (definition.superClass) {
cls.prototype.super = new classList[definition.superClass]();
}
classList[definition.name] = cls;
cls.constructor = cls;
for (i = 0; i < definition.methods.length; i++) {
method = definition.methods[i];
cls.prototype[method.name] = Function(method.code);
}
}
// -- Here you need to get data from your database --
// Super Class
registerClass({
name: "SuperClass",
methods: [{
name: "greet",
code: "console.log(\"Super hello\");"
}]
});
// Sub Class
registerClass({
name: "SubClass",
superClass: "SuperClass",
methods: [{
name: "greet",
code: "this.super.greet(); console.log(\"Sub hello\");"
}]
});
// Usage
var obj = new classList.SubClass();
obj.greet();
&#13;