JavaScript中私有字段处理不符合预期的原因是什么?
问题分析与解决方案
错误根源
报错源于类初始化顺序导致私有字段未完成初始化时被提前访问。
创建WfApp实例的执行流程:
- 进入
WfApp构造函数,调用super(config) - 进入
WfStateful构造函数,调用super(config) - 进入
WfConfigurable构造函数,执行this._init(config) _init调用this.configure(config),此时this指向WfApp实例- 执行
WfStateful的configure方法,调用suspendSave() suspendSave尝试访问私有字段#saveSuspend,但此时WfStateful的私有字段还未初始化——JavaScript中,子类构造函数里必须先完成super()调用,才会初始化当前类的实例字段(包括私有字段),而这里在super()执行过程中就提前触发了私有字段的访问,导致报错。
对比可运行示例的差异
第二个示例中,B类实例调用b.priv是在实例完全初始化之后:
B的构造函数调用super()完成后,A类的私有字段#priv已经初始化- 后续通过getter/setter访问私有字段时,实例已经完成所有初始化步骤,因此不会报错。
修复方案
调整初始化逻辑,将configure的调用延迟到子类构造函数的super()之后,确保私有字段已经初始化。修改后的代码如下:
class WfConfigurable { constructor(config) { // 移除父类构造函数中的_init调用,交由子类控制初始化时机 } _init(config) { this.configure(config); } configure(config) {} } class WfStateful extends WfConfigurable { #saveSuspend = 0; constructor(config) { super(config); // 在super()调用完成后,私有字段已初始化,再执行初始化逻辑 this._init(config); } get saving() { return this.#saveSuspend == 0; } configure(config) { this.suspendSave(); super.configure(config); this.continueSave(); } suspendSave() { this.#saveSuspend++; } continueSave(force) { if (force) { this.#saveSuspend = 0; } else { this.#saveSuspend = Math.max(this.#saveSuspend - 1, 0); } } } class WfApp extends WfStateful { constructor(config) { super(config); } } const wfApp = new WfApp({});
内容的提问来源于stack exchange,提问作者Nagy Zoltán
相关产品推荐
相关产品推荐

