必须同步调用 super(),因为 es 规范要求子类构造函数内 this 只有在 super() 执行后才有效;微任务异步执行时构造函数已返回,此时 this 语义上不存在,直接报错。

在 JavaScript 中,子类构造函数中必须在使用 this 之前调用 super(),这是语法强制要求。但如果你尝试把 super() 延迟到微任务(如 Promise.then、queueMicrotask)中执行,会直接报错:ReferenceError: Must call super constructor in derived class before accessing 'this' or returning from derived constructor。这不是运行时“边界限制”可以绕开的问题,而是语言规范层面的硬性约束。
为什么不能在微任务里调用 super()
ES 规范规定:子类构造函数执行期间,若未完成 super() 调用,内部的 [[ConstructState]] 状态就一直是 undefined,此时任何对 this 的访问(包括隐式访问,比如进入对象方法、设置属性、甚至只是 return this)都会触发该错误。微任务是异步执行的,等它运行时,构造函数早已同步返回——而此时实例根本没完成初始化,this 在语义上还不存在。
常见误用场景与替代方案
你可能想这么做,是因为需要异步获取某些数据再传给父类,例如:
- 从 API 加载配置后初始化父类
- 等待某个 Promise 就绪后再调用
super(config) - 在装饰器或元编程中延迟构造逻辑
这些需求都不能靠“延迟 super”实现。正确做法是:
-
把异步逻辑移出构造函数:先同步调用
super(),再在实例上启动异步流程(比如在构造函数里调用this.init(),而init()返回 Promise) - 用工厂函数封装异步创建过程:不直接 new 子类,而是写一个 async 函数,先 await 所需数据,再同步 new 实例并传入
-
父类设计支持延迟初始化:让父类构造函数接受 partial config 或 null,并提供
ready()/setup()方法供后续补全
示例:用工厂函数安全实现异步构造
✅ 正确方式:
class Parent {
constructor(data) {
this.data = data;
}
}
class Child extends Parent {
constructor(data) {
super(data); // 必须同步调用
}
}
// 工厂函数替代 new Child()
async function createChild() {
const data = await fetch('/api/config').then(r => r.json());
return new Child(data); // 此时 super 可同步调用
}
补充说明:static 方法和继承链中的 super
如果问题不是出现在构造函数,而是子类的 static 方法里调用 super.xxx(),那不受此限制——static 方法中 super 是正常绑定的,和是否在微任务中无关。只要确保调用时上下文(即 super 所指的父类)存在且方法已定义即可。
不复杂但容易忽略:super 不是普通函数调用,它是构造过程的准入凭证。微任务再快,也快不过 JS 引擎对「构造阶段完整性」的检查。










