手动实现扩展/超级

时间:2016-10-18 15:54:36

标签: javascript prototype-pattern

我正在根据从数据库中提取的描述性数据动态构建类。例如,如果数据如下:

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 来工作。提示?

2 个答案:

答案 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;
&#13;
&#13;