我正在创建一个库,我想在其中提供一个帮助器来扩展基类,以便用户即使自己不使用 ES2015 也可以扩展它。问题是,如果基类恰好在 ES2015 中(因为它不是通过转译器发送),我从子类调用父构造函数会失败:
Class constructor Foo cannot be invoked without 'new'
我想要实现的目标的示例:
class Foo {
constructor() {
console.log("In Foo");
}
superMethod() {
return console.log("In super method");
}
static classMethod() {
return console.log("In class method");
}
}
Foo.extendClass = function (constructor, methods) {
const currentClass = this;
if (typeof constructor !== 'function') {
methods = constructor;
constructor = function () {
return Object.getPrototypeOf(constructor).apply(this, arguments);
};
}
constructor.prototype = Object.create(currentClass.prototype, {
constructor: {
value: constructor,
writable: true,
configurable: true
}
});
Object.setPrototypeOf(constructor, currentClass);
Object.assign(constructor.prototype, methods);
return constructor;
};
const Bar = Foo.extendClass({
subMethod: function() {
return console.log("In sub method");
}
});
b = new Bar();
问题出在这一行:
return Object.getPrototypeOf(constructor).apply(this, arguments);
那么我如何调用父级的构造函数呢?我以为ES2015只是标准原型(prototype)继承之上的一个糖,但看起来你不能模拟它?还有另一种方法可以在运行时定义子类吗?
最佳答案
ES6 在 [[Call]]
和 [[Construct]]
操作之间创建了更清晰的区别。 ES6 类只能使用 [[Construct]]
操作来构造,但 .call
/.apply
是 [[Call] ]
操作。要使用 [[Construct]]
,您需要使用 Reflect.construct()
创建新实例。例如
constructor = function () {
return Reflect.construct(Object.getPrototypeOf(constructor), arguments);
};
或
constructor = function () {
return Reflect.construct(currentClass, arguments);
};
不过我还要注意,这也忽略了 ES6 中的另一个新功能,即 new.target
。您还需要通过执行以下操作来保留它
constructor = function () {
return Reflect.construct(currentClass, arguments, new.target);
};
确保事物的行为方式与类语法相同。
另请注意,您不得在此函数内使用this
。 Reflect.construct
的返回值是新实例,因此如果您想在自己的自定义构造函数中使用它,您需要这样做
constructor = function () {
const _this = Reflect.construct(currentClass, arguments, new.target);
_this.foo = "foo";
return _this;
};
但是,如果你仔细想想,这本质上和做事情是一样的
constructor = class extends currentClass {}
关于javascript - 通过原型(prototype)继承扩展ES2015,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58050619/