JavaScript父类构造函数无法访问子类字段及setTimeout方案原理咨询
JavaScript父类构造函数访问子类类字段问题原理说明
问题1:为什么父类构造函数无法访问子类的字段?
这是由ES标准中规定的类实例初始化顺序决定的,子类实例化时的执行顺序严格如下:
- 触发
new Child()调用,进入子类Child的构造函数 - 子类构造函数第一行执行
super(),跳转到父类Parent的构造函数执行 - 父类构造函数执行期间,子类的类字段还未完成初始化赋值
- 父类构造函数执行完毕,返回当前实例后,才会按顺序执行子类声明的类字段赋值(也就是
x = 5这一步才会被执行) - 子类构造函数中
super()之后的剩余代码执行
你给出的第一个示例中,父类构造函数打印this.x时,子类的x字段还没被赋值到实例上,所以输出为undefined:
class Parent { constructor() { console.log(this.x); } } class Child extends Parent { x = 5; constructor() { super(); } } // 输出:undefined
而init方法的方案可行,是因为this.init()是在super()执行完成后才调用的,此时子类类字段已经完成赋值,所以可以正常访问到x的值:
class Parent { init() { console.log(this.x); } } class Child extends Parent { x = 5; constructor() { super(); this.init(); } } // 输出:5
问题2:为什么添加setTimeout函数后就可以访问子类字段?
这是由JavaScript的事件循环机制决定的:
setTimeout属于异步宏任务,即便设置延迟为0,回调函数也不会在当前同步执行栈中运行,会被推入宏任务队列等待执行- 只有当前同步执行栈中的所有代码全部执行完毕后,才会从宏任务队列中取出等待的回调执行
- 当
setTimeout的回调运行时,整个子类构造流程已经全部完成,子类的类字段早已完成赋值,所以可以正常读取到this.x的值
注:你给出的示例中存在笔误,setTimout正确拼写为setTimeout,修正后代码如下:
class Parent { constructor() { setTimeout(() => console.log(this.x), 0); } } class Child extends Parent { x = 5; constructor() { super(); } } // 输出:5
内容的提问来源于stack exchange,提问作者Meet Shah
相关产品推荐
相关产品推荐

