简体   繁体   English

如果在继承 class 中重新定义该字段,则无法从 super 的构造函数设置公共 class 字段的值

[英]Inability to set value of public class field from constructor of super if that field is redefined in the inheriting class

I use polymorphism with JSDoc to describe concrete implementations of some classes.我使用 JSDoc 的多态性来描述一些类的具体实现。 Up until now I have been doing this with getters and setters;到目前为止,我一直在用 getter 和 setter 做这件事; newly implemented public class fields can shorten this getter and setter boilerplate considerably.新实现的公共 class 字段可以大大缩短这个 getter 和 setter 样板。

My problem is described by the code snippet below.下面的代码片段描述了我的问题。 The value set in the constructor does not survive the redefining of the public class field.构造函数中设置的值在重新定义公共 class 字段后无法保留。 How can I redefine a public class field in an inheriting class and keep the value set in the super constructor?如何在继承的 class 中重新定义公共 class 字段并保留在超级构造函数中设置的值? Is this a bug in public class fields?这是公共 class 字段中的错误吗?

 class ThingHolder { /**@type {notKnownYet}*/ publicFieldForThing constructor(thing) { this.publicFieldForThing = thing //Do stuff for all thing holders } dropMyThing() { //Throw not implemented } setThingField(thing) { this.publicFieldForThing = thing } } class RedThingHolder extends ThingHolder { /**@type {RedThing}*/ publicFieldForThing dropMyThing() { //functionality for dropping a red thing with JSDoc niceties for RedThings } } class BlueThingHolder extends ThingHolder { /**@type {BlueThing}*/ publicFieldForThing dropMyThing() { //functionality for dropping a blue thing with JSDoc niceties for BlueThings } } const redThing = { colour: "red" } //Setting the thing in the constructor results in unextected behaviour const redThingHolder = new RedThingHolder(redThing) console.assert(redThingHolder.publicFieldForThing === redThing) //Setting the thing through an inherited method after construction works perfectly fine redThingHolder.setThingField(redThing) console.assert(redThingHolder.publicFieldForThing === redThing)

Edit: This question was not about my motivations.编辑:这个问题与我的动机无关。 Why do public fields behave differently to getters with regard to the prototype chain?为什么关于原型链,公共字段与 getter 的行为不同?

 class Parent { constructor() { console.log("prop in instance during super: ", "prop" in this) console.log("publicField in instance during super: ", "publicField" in this) } } class Child extends Parent { constructor() { super() console.log("prop in instance after super: ", "prop" in this) console.log("publicField in instance after super: ", "publicField" in this) } publicField get prop() { } } new Child

When you call the constructor of RedThingHolder class当你调用RedThingHolder class 的构造函数时

new RedThingHolder(redThing)

the default constructor of RedThingHolder will pass the parameter redThing to the super class' constructor which will add a property publicFieldForThing on the newly created object. RedThingHolder的默认构造函数会将参数redThing传递给超类的构造函数,该构造函数将在新创建的 object 上添加属性publicFieldForThing

Re-definition of publicFieldForThing in child classes overwrites the publicFieldForThing set inside the super class.在子类中重新定义publicFieldForThing覆盖publicFieldForThing中设置的 publicFieldForThing。

I feel like this is a bug and that the value should be retained automatically.我觉得这是一个错误,应该自动保留该值。

Its not a bug and redefining a property with the same name will not retain a value because you are defining a field with a name that already exists on an object.它不是错误,重新定义具有相同名称的属性将不会保留值,因为您正在定义一个名称已存在于 object 上的字段。 Instead of retaining , it will overwrite the existing field.它不会保留,而是覆盖现有字段。

Doing this这样做

class RedThingHolder {
   publicFieldForThing;
   ...
}

will overwrite the publicFieldForThing field with the default value of undefined .将使用默认值undefined覆盖publicFieldForThing字段。

How can I redefine a public class field in an inheriting class and keep the value set in the super constructor?如何在继承的 class 中重新定义公共 class 字段并保留在超级构造函数中设置的值?

You can set the publicFieldForThing in the child class constructor using the getter for publicFieldForThing defined in the super class.您可以使用在超级publicFieldForThing publicFieldForThing getter 在子 class 构造函数中设置 publicFieldForThing。

 class ThingHolder { constructor(thing) { this.publicFieldForThing = thing; } get publicField() { return this.publicFieldForThing; } } class RedThingHolder extends ThingHolder { constructor(thing) { super(thing); this.publicFieldForThing = this.publicField; } } const redThing = { colour: 'red', }; const redThingHolder = new RedThingHolder(redThing); console.log(redThingHolder.publicFieldForThing === redThing);

Edit编辑

Why do public fields behave differently to getters with regard to the prototype chain?为什么关于原型链,公共字段与 getter 的行为不同?

getter/setters in ES2015's classes are added on the proptotype object whereas the public fields are added on the object itself. ES2015 类中的 getter/setter 被添加到原型 object 上,而公共字段被添加到 object 本身上。

In the code example you posted, prop is added on the Child.prototype whereas the publicField is like doing在您发布的代码示例中,在Child.prototype上添加了prop ,而publicField就像在做

this.publicField = undefined;

in the constructor of the Child class just after the super() call.super()调用之后Child class 的构造函数中。

This is why "prop" in this inside the constructor of the Parent class returns true whereas "publicField" in this evaluates to true only inside the constructor of the Child class.这就是为什么Parent class 的构造函数中的"prop" in this返回true ,而其中的"publicField" in this仅在Child class 的构造函数中计算为true

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM