构造函数调用派生类重写方法时字段初始化异常问题咨询
JavaScript类字段初始化与构造函数执行顺序的坑
你碰到的这两个问题,核心原因都是JavaScript类字段(Class Fields)的初始化时机晚于父类构造函数的执行。创建子类实例时,代码的执行顺序有固定逻辑,咱们拆解来看:
- 先调用子类的
super()(不管你显式写没写,子类构造函数都会隐式触发父类构造函数) - 父类构造函数执行完毕后,才会初始化子类的类字段
- 最后执行子类构造函数里
super()之后的代码
示例一为什么输出false?
看这段代码:
class a { constructor () { this.load() } load () {} } class b extends a { loaded = false; load () { this.loaded = true } } const bInstance = new b() console.log(bInstance.loaded);
执行流程一步步拆解:
- 新建
b实例时,先触发父类a的构造函数,里面调用了this.load()——这里的this是子类b的实例,所以实际执行的是子类的load方法,把this.loaded设为true - 父类构造函数跑完后,轮到初始化子类的类字段
loaded = false,这一步直接覆盖了之前设置的true - 最后
console.log自然输出false
示例二为什么先输出undefined?
再看这段代码:
class a { a = true; constructor () { this.load() } load () {} } class b extends a { b = true; load () { console.log(this.a, this.b) } } const bInstance = new b()
执行步骤:
- 新建
b实例,先调用super()触发父类a的构造函数:父类先初始化自己的类字段a = true,然后调用this.load(),此时执行的是子类b的load方法 - 这时候子类
b的类字段b还没开始初始化,所以this.b是undefined,console.log就打出了true undefined - 父类构造函数执行完毕后,子类才初始化
b = true,所以最终实例的bInstance.b值为true
解决方案
如果想让父类构造函数调用的方法能访问到子类的类字段,有两种常用处理方式:
- 把子类的类字段初始化逻辑放到子类构造函数中,并且必须放在
super()之后:class b extends a { constructor() { super(); this.loaded = false; } load () { this.loaded = true } } - 避免在父类构造函数中直接调用可能被子类重写的方法,改成在子类构造函数中手动调用父类方法,或者用
setTimeout延迟执行(异步方案,按需选择)
内容的提问来源于stack exchange,提问作者Dinhero21
相关产品推荐
相关产品推荐

