JavaScript,扩展ES6类的setter将继承getter

17

在JavaScript中,使用以下示例代码:

class Base {
   constructor() {  this._val = 1   }
   get val()     { return this._val }
}

class Xtnd extends Base {
   set val(v)    { this._val = v }
}

let x = new Xtnd();
x.val = 5;
console.log(x.val);  // prints 'undefined'

实例x将不会从Base类继承get val()...。在这种情况下,Javascript把缺少getter的情况看作undefined。

我有很多类都具有相同的一组getter,但拥有独特的setter。目前,我只是在每个类中复制getter,但我正在重构代码,想消除冗余代码。

是否有一种方法告诉JS保留基类的getter,或者是否有一个优雅的解决方案来解决这个问题?


为了以后参考,这个问题与 [tag:redundancy] 标签无关,该标签是指有意复制代码以使关键部分更加健壮。我相信你想使用的是 [tag:boilerplate],它是指看似不必要的代码重复。 - Patrick Roberts
“我有这样一种情况,我有许多类,它们都具有完全相同的getter集合,但是setter却是独特的。” - 你真的需要继承吗?如果你只想避免重复,JS有很多其他共享代码的方法。 - Bergi
1
“有没有办法告诉JS保留基类中的getter?” - 不,这是设计上的限制 - Bergi
1个回答

17
这个限制是由JavaScript在幕后处理属性访问器的方式引起的。在ECMAScript 5中,您最终会得到一个原型链,其中包含一个属性描述符,用于val,该描述符具有由您的类定义的get方法和未定义的set方法。
在您的Xtnd类中,您还有另一个属性描述符用于val,它遮蔽了基类的整个属性描述符,包含一个由类定义的set方法和一个未定义的get方法。
为了将getter转发到基类实现,每个子类中都需要一些样板文件,但至少不必复制实现本身:

class Base {
   constructor() {  this._val = 1   }
   get val()     { return this._val }
}

class Xtnd extends Base {
   get val()     { return super.val }
   set val(v)    { this._val = v }
}

let x = new Xtnd();
x.val = 5;
console.log(x.val);  // prints '5'


这个半满意的解决方案可行。谢谢。...但仍然希望能有更加优雅的解决方案。 - codechimp
@codechimp 你在使用翻译器吗?如果是的话,我可以添加另一个解决方案,使用类装饰器和/或方法装饰器将属性访问器转发到基类。这听起来像是对你有益的东西吗? - Patrick Roberts
Transpilier是我想到的一个解决方案,但我还在抵制使用它。我理解它的价值,但我想保持这个代码库纯粹的vanilla JS。 - codechimp
这个this._val = v让我感到不舒服。我会写成super._val = v - ceving
@ceving那个评论更适合放在问题上,我故意没有改变它,这样我的答案就不会掩盖代码中真正需要改变的部分,以实现预期的效果。 - Patrick Roberts
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接