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
相关产品推荐
相关产品推荐

