考虑以下:
class Base {
_value;
constructor() {
this._value = 1;
}
get value() { return this._value; }
set value(v) { this._value = v; }
}
class Derived extends Base {
set value(v) {
// ...
super.value = v;
}
}
const d = new Derived();
d.value = 2;
console.log(d.value); // <-- undefined
我期待
Base
的“getter”方法在 Derived
的类中“继承”的类,因此显示 2
的值而不是 undefined
.似乎“getter”或“setter”方法都不是独立继承的,而是被共同视为一个实体。从某种意义上说,如果重写的 setter 方法不存在,或者它与相应的 getter 耦合(具体在派生类中声明,而不是被继承),如下所示:get value() { return super.value; }
那么,就不会有这样的问题了。
那么,为什么 getter 或 setter 不是独立继承的,因为它们应该解耦读取和设置字段的概念?
最佳答案
JavaScript 的类继承使用原型(prototype)链来连接子 Constructor.prototype
给家长Constructor.prototype
为代表团。通常,super()
构造函数也被调用。这些步骤形成了单祖先父/子层次结构,并创建了 OO 设计中可用的最紧密耦合。
我建议你阅读一篇关于 Master the JavaScript Interview: What’s the Difference Between Class & Prototypal Inheritance? 的非常好的文章埃里克·埃利奥特 (Eric Elliott) 撰写。
更新
用于详细说明;这是预期的行为,因为您正在向 Derived.prototype
添加新描述符.当您使用 get
添加描述符时或 set
,实际上有一个使用该名称创建的函数,因此如果未设置,它将评估为未定义。它变得像一个自己的属性(property)。
Standard ECMA-262
14.3.9 Runtime Semantics: PropertyDefinitionEvaluation
- MethodDefinition :
set
PropertyName ( PropertySetParameterList ) { FunctionBody }- Let propKey be the result of evaluating PropertyName. ReturnIfAbrupt(propKey).
- If the function code for this MethodDefinition is strict mode code, let strict be true. Otherwise let strict be false.
- Let scope be the running execution context’s LexicalEnvironment.
- Let formalParameterList be the production FormalParameters : [empty]
- Let closure be FunctionCreate(Method, PropertySetParameterList, FunctionBody, scope, strict).
- Perform MakeMethod(closure, object).
- Perform SetFunctionName(closure, propKey,
"set"
).- Let desc be the PropertyDescriptor{[[Set]]: closure, [[Enumerable]]: enumerable, [[Configurable]]: true}
- Return DefinePropertyOrThrow(object, propKey, desc).
6.2.4.6 CompletePropertyDescriptor ( Desc )
When the abstract operation CompletePropertyDescriptor is called with Property Descriptor Desc the following steps are taken:
- ReturnIfAbrupt(Desc).
- Assert: Desc is a Property Descriptor
- Let like be Record{[[Value]]: undefined, [[Writable]]: false, [[Get]]: undefined, [[Set]]: undefined, [[Enumerable]]: false, [[Configurable]]: false}.
- If either IsGenericDescriptor(Desc) or IsDataDescriptor(Desc) is true, then
- a. If Desc does not have a [[Value]] field, set Desc.[[Value]] to like.[[Value]].
- b. If Desc does not have a [[Writable]] field, set Desc.[[Writable]] to like.[[Writable]].
- Else,
- a. If Desc does not have a [[Get]] field, set Desc.[[Get]] to like.[[Get]].
- b. If Desc does not have a [[Set]] field, set Desc.[[Set]] to like.[[Set]].
- If Desc does not have an [[Enumerable]] field, set Desc.[[Enumerable]] to like.[[Enumerable]].
- If Desc does not have a [[Configurable]] field, set Desc.[[Configurable]] to like.[[Configurable]].
- Return Desc.
也看看6.1.7.2 Object Internal Methods and Internal Slots在 Table 5 - Essential Internal Methods尤其是
GetOwnProperty
和 DefineOwnProperty
.[[GetOwnProperty]] (propertyKey) → Undefined | Property Descriptor
Return a Property Descriptor for the own property of this object whose key is propertyKey, or undefined if no such property exists.
[[DefineOwnProperty]] (propertyKey, PropertyDescriptor) → Boolean
Create or alter the own property, whose key is propertyKey, to have the state described by PropertyDescriptor. Return true if that property was successfully created/updated or false if the property could not be created or updated.
关于javascript - 为什么 getter 或 setter 在 JavaScript 中不能独立继承?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60899900/