ES6 class继承必须在子类constructor中先调super()初始化this,否则报ReferenceError;super还可调父类方法,且ES6自动维护静态和原型链继承关系。

ES6 的 class 语法只是原型继承的语法糖,它本身不改变 JavaScript 继承的本质——所有继承最终都落在 [[Prototype]] 链上。直接用 class + extends 是最简明、最安全的写法,但必须理解 super() 的调用时机和限制。
为什么子类构造函数里必须调用 super()
在子类 constructor 中,this 在调用 super() 前是未初始化的(ReferenceError)。这是 ES6 强制的时序约束,不是可选习惯。
-
super()必须在访问this之前执行,哪怕只是console.log(this) - 如果子类没写
constructor,JS 会自动补一个隐式构造函数并调用super(...args) - 如果写了
constructor却没调用super(),运行时直接报错:ReferenceError: Must call super constructor in derived class before accessing 'this' or returning from derived constructor
class Parent {
constructor(name) {
this.name = name;
}
}
class Child extends Parent {
constructor(name, age) {
// ❌ 错误:不能在 super() 前使用 this
// console.log(this);
super(name); // ✅ 必须第一句(或至少在任何 this 访问前)
this.age = age; // ✅ 此时 this 已就绪
}
}
super 不只是调构造函数,还能调父类方法
super 在方法内部指向父类的原型对象(即 Parent.prototype),可用于显式调用被重写的父方法,而不是仅限于构造函数中。
- 在实例方法中用
super.methodName()调用父类同名方法 - 在静态方法中用
super.staticMethod()调用父类静态方法 -
super在箭头函数里不可用(因为箭头函数没有自己的this和super绑定)
class Animal {
speak() {
return "Animal speaks";
}
static type() {
return "Animal";
}
}
class Dog extends Animal {
speak() {
return super.speak() + " — woof!"; // ✅ 调用父类实例方法
}
static type() {
return "Dog (" + super.type() + ")"; // ✅ 调用父类静态方法
}
}
ES6 继承与传统原型链继承的关键差异
ES6 class 继承强制要求子类构造函数通过 super() 初始化 this,而手写原型链(如 Child.prototype = Object.create(Parent.prototype))容易漏掉 constructor 指针修复或忘记在子构造函数里手动调 Parent.call(this, ...)。
立即学习“Java免费学习笔记(深入)”;
- ES6 自动设置
Child.__proto__ === Parent(静态继承),传统方式需手动设置 - ES6 自动保证
Child.prototype.__proto__ === Parent.prototype(原型链继承),传统方式易出错 - ES6 子类无法用
new Parent()替代super();手写时若漏掉Parent.call(this),this就不会拥有父类实例属性 - ES6 类内部方法默认不可枚举(
Object.keys()看不到),传统prototype上挂的方法默认可枚举
兼容性与真实项目中的取舍
现代浏览器和 Node.js(≥ v6)原生支持 class/extends,Babel 编译后会降级为 function + Object.setPrototypeOf 或 __proto__ 设置,但某些老环境(如 IE)仍需完全避免。
- 若需支持 IE11,不能依赖
class语法,得用 Babel + @babel/preset-env 配置目标环境 - 注意:Babel 编译后的
super调用会被转成 helper 函数(如_getPrototypeOf),调试时堆栈可能变深 - TypeScript 用户无需担心语法兼容性,但要注意
super()的调用位置检查是在编译期强制的
真正容易被忽略的是:子类 constructor 中哪怕只写 return {},也必须先调 super();否则不是逻辑错误,而是语法级禁止。










