[英]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);
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.