首页 > 解决方案 > 为什么 getter 或 setter 在 JavaScript 中不能独立继承?

问题描述

考虑以下:

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

我希望类的“getter”方法在 的Base类中被“继承”Derived因此显示的值2而不是undefined。似乎“getter”或“setter”方法都不是独立继承的,而是被共同视为一个实体。从某种意义上说,如果重写的 setter 方法不存在,或者它与相应的 getter 耦合(具体在派生类中声明,而不是被继承),如下所示:

get value() { return super.value; }

那么,就不会有这样的问题了。

那么,为什么 getter 或 setter 不是独立继承的,因为它们应该解耦读取设置字段的概念?

标签: javascriptoopinheritancegetter-setter

解决方案


JavaScript 的类继承使用原型链将子级Constructor.prototype连接到父级Constructor.prototype以进行委托。通常,super()构造函数也被调用。这些步骤形成了单祖先父/子层次结构,并创建了 OO 设计中可用的最紧密耦合。

我建议你阅读一篇关于掌握 JavaScript 面试的非常好的文章:类和原型继承之间有什么区别?埃里克·埃利奥特 (Eric Elliott) 撰写。

更新

用于详细说明;这是预期的行为,因为您正在向Derived.prototype. 当您使用getor添加描述符时set,实际上有一个使用该名称创建的函数,因此如果未设置,它将评估为未定义。它变得像一个自己的财产。

标准 ECMA-262

14.3.9运行时语义:PropertyDefinitionEvaluation

  1. MethodDefinition : set PropertyName ( PropertySetParameterList ) { FunctionBody }
  2. propKey成为评估PropertyName的结果。 ReturnIfAbrupt ( propKey )。
  3. 如果此MethodDefinition的功能代码是严格模式代码,则让strict。否则让strictfalse
  4. scope正在运行的执行上下文LexicalEnvironment
  5. formalParameterList成为生产形式FormalParameters:[空]
  6. 闭包FunctionCreate (Method, PropertySetParameterList , FunctionBody , scope , strict )。
  7. 执行MakeMethod闭包对象)。
  8. 执行SetFunctionName ( closure , propKey , "set")。
  9. desc为 PropertyDescriptor{[[Set]]: closure , [[Enumerable]]: enumerable , [[Configurable]]: true }
  10. 返回DefinePropertyOrThrow ( object , propKey , desc )。

6.2.4.6 CompletePropertyDescriptor(描述)

当使用Property Descriptor Desc调用抽象操作 CompletePropertyDescriptor 时,将执行以下步骤:

  1. ReturnIfAbrupt (描述)。
  2. 断言Desc是一个属性描述符
  3. like成为 Record{[[Value]]: undefined , [[Writable]]: false , [[Get]]: undefined , [[Set]]: undefined , [[Enumerable]]: false , [[Configurable]] :}。
  4. 如果IsGenericDescriptor ( Desc ) 或IsDataDescriptor ( Desc ) 为真,则
    • 一个。如果Desc没有 [[Value]] 字段,请将Desc .[[Value]] 设置为like .[[Value]]。
    • 湾。如果Desc没有 [[Writable]] 字段,请将Desc .[[Writable]] 设置为like .[[Writable]]。
  5. 别的,
    • 一个。如果Desc没有 [[Get]] 字段,请将Desc .[[Get]] 设置为like .[[Get]]。
    • 湾。如果Desc没有 [[Set]] 字段,请将Desc .[[Set]] 设置为like .[[Set]]。
  6. 如果Desc没有 [[Enumerable]] 字段,请将Desc .[[Enumerable]] 设置为like .[[Enumerable]]。
  7. 如果Desc没有 [[Configurable]] 字段,请将Desc .[[Configurable]] 设置为like .[[Configurable]]。
  8. 返回描述

还可以查看表 5 - 基本内部方法中的6.1.7.2对象内部方法和内部槽,尤其是和。GetOwnPropertyDefineOwnProperty

[[GetOwnProperty]] (propertyKey) → 未定义 | 属性描述符

返回此对象自己的属性的属性描述符,其键为propertyKey,如果不存在此类属性,则返回undefined 。

[[DefineOwnProperty]] (propertyKey, PropertyDescriptor) → 布尔值

创建或更改自己的属性,其键为propertyKey,以具有由PropertyDescriptor描述的状态。如果该属性已成功创建/更新,则返回true ;如果无法创建或更新该属性,则返回false 。


推荐阅读