问题
I have an old codebase full of subclasses of a some external class, using prototypal inheritance. Recently, this external class has been ported to an ES6 class, but also has new features I'd like to use. Prototypal inheritance doesn't work anymore, and I'm wondering if it's possible to make it work even if it's with some ugly hack. This is basically what I'm trying to do:
class ClassParent {
constructor(a) {
this.a = a;
}
}
var ProtoChildFromClassParent = function(a) {
ClassParent.call(this, a);
}
ProtoChildFromClassParent.prototype = Object.create(ClassParent.prototype);
ProtoChildFromClassParent.prototype.constructor = ProtoChildFromClassParent;
var child = new ProtoChildFromClassParent(4);
console.log(child.a);
I get the following error:
ClassParent.call(this, a);
^
TypeError: Class constructor ClassParent cannot be invoked without 'new'
Please don't post answers like "you should port your subclasses to ES6". I know that's probably the appropriate thing to do, take this question more as a learning exercise / curiosity about JS internals.
回答1:
Since you're running this all on an environment that actually supports real ES6 classes, you may be able to achieve what you're looking for. What you'll need to do is to change your subclass logic to be
var ProtoChildFromClassParent = function(a) {
const _this = Reflect.construct(ClassParent, [a], new.target);
return _this;
}
Object.setPrototypeOf(ProtoChildFromClassParent, ClassParent);
Object.setPrototypeOf(ProtoChildFromClassParent.prototype, ClassParent.prototype);
This is predicated on Reflect.construct
being available, so it will not work on an older ES5 environment, but then neither would ES6 class syntax either. It's also important that new.target
be available. As long as both are available, this is very close to replicating the behavior you'd get from using actual class syntax. That said, immediately the question would be why you're not just doing
class ProtoChildFromClassParent extends ClassParent {}
so whether this is useful or not really depends on what's stopping you from doing that to begin with.
回答2:
I was also interested on how to inherit in prototypical way from ES6 class, just to understand more in JS and here what I can propose:
class Parent {
constructor(data){
this.#setPrivateProperty(data);
}
#privateProperty = "Parent private property";
#setPrivateProperty = (data)=>{
this.#privateProperty = data;
}
parentPublicMethod = ()=>{
console.log("Parent public method responded:", this.#privateProperty);
}
}
function Child(data, parentData){
this.__proto__ = new Parent(parentData)
this.childPublicProperty = data;
}
Child.prototype = Parent.prototype;
Child.prototype.constructor = Child;
let c = new Child("Child data", "Parent data");
// Output: "Parent public method responded: Parent data"
c.parentPublicMethod();
// Output: "Child public property value is: Child data"
console.log("Child public property value is:", c.childPublicProperty);
// Output: "1. Instance of Child: true 2. Instance of Parent: true"
console.log("1. Instance of Child:", c instanceof Child, "2. Instance of Parent:", c instanceof Parent);
I will be very grateful to those people, who will criticize this code sample and maybe we get some more details. Thanks to All in advance!!!
回答3:
class
is just a friendlier syntax for older constructor function patterns.
i.e.:
const x = function () {};
const y = new x();
Is the same as:
class x {
constructor () {}
}
const y = new x();
y.prototype
refers to the constructor method of the x
class.
来源:https://stackoverflow.com/questions/51344127/proto-inheritance-from-es6-class