You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

JavaScript含私有变量与getter/setter的类继承问题

问题根源与解决方案

首先得明确:你遇到的问题核心是JavaScript私有字段(#开头)的特性——它们是完全私有的,子类既无法访问父类的私有字段,也不能继承这些字段。而你在子类AtypicalSurfaceWork里重新声明了和父类同名的#id、#x等私有字段,这些其实是子类自己的独立字段,和父类的私有字段毫无关联。这就导致:

  • 父类的getter访问的是父类自己的#x/#y,但子类的setter修改的是子类自己的#x/#y,两者数据不互通,自然get的时候返回undefined
  • 父类的getter/setter本身是可以被继承的,但你的子类操作的是自己的私有字段,相当于绕过了父类的逻辑

解决步骤

1. 删除子类中重复的私有字段声明

子类只需要声明自己独有的私有字段(比如#eventSender),父类的#id、#x等字段不需要重复声明——你根本没法访问它们,声明了只会创建独立的冗余字段。

2. 重写setter时通过super调用父类的setter

当你需要在子类的setter里扩展逻辑(比如触发事件),必须通过super.x = value来调用父类的setter,这样才能正确更新父类的私有字段,同时触发父类的calculate()方法。

修改后的完整代码

// 基础模型类不变
class Surface {
  #id; #name; #x; #y; #value; #periphery;
  constructor({ id, name, x, y }) {
    this.#id = id;
    this.#name = name;
    this.#x = x || 0;
    this.#y = y || 0;
    this.calculate();
  }
  calculate() {
    this.#value = this.#x * this.#y;
    this.#periphery = 2 * (this.#x + this.#y);
  }
  set x(value) {
    this.#x = parseFloat(value || 0);
    this.calculate();
  }
  set y(value) {
    this.#y = parseFloat(value || 0);
    this.calculate();
  }
  get id() { return this.#id; }
  get name() { return this.#name; }
  get x() { return this.#x.toFixedNumber(2); }
  get y() { return this.#y.toFixedNumber(2); }
  get value() { return this.#value.toFixedNumber(2); }
  get periphery() { return this.#periphery.toFixedNumber(2); }
  toJSON() {
    return { "id": this.#id, "name": this.#name, "x": this.#x, "y": this.#y };
  }
}

// 修改后的子类
class AtypicalSurfaceWork extends Surface {
  #eventSender; // 仅保留子类独有的私有字段
  constructor({ id, name, x, y, eventSender }) {
    super({ id, name, x, y });
    this.#eventSender = eventSender;
  }

  set x(value) {
    console.log("Test x");
    // 调用父类setter更新父类私有字段
    super.x = value;
    this.#eventSender.emit("calculate");
  }

  set y(value) {
    console.log("Test y");
    super.y = value;
    this.#eventSender.emit("calculate");
  }

  get surface() { return this.value; }
}

关键说明

  • 父类的getter会正常继承,无需重写——它们访问的是父类的私有字段,而子类通过super调用父类setter时已经正确更新了这些字段
  • 如果你需要子类能直接操作父类的内部数据,私有字段就不适合了,可以改用受保护字段约定(比如用_x、_y开头,虽然不是真正私有,但业内约定子类可以访问这些字段),但坚持用私有字段的话,就必须通过父类的公共接口(getter/setter)来交互
  • 现在子类的setter既保留了父类的逻辑(更新字段、触发计算),又扩展了自己的事件触发逻辑,同时getter能正常返回正确的值

内容的提问来源于stack exchange,提问作者Hejtmus

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.08 14:12:42