ES6 class是函数和原型链的语法糖,继承仍基于[[Prototype]]链:①B.prototype.[[Prototype]]=A.prototype;②B.[[Prototype]]=A;③子类constructor必须先调super()初始化this。

ES6 class 不是新继承机制,只是函数和原型链的语法糖
ES6 的 class 本身不改变 JavaScript 的继承本质——它依然完全基于原型(prototype)和 [[Prototype]] 链。所谓“类继承”,底层仍是通过 Object.setPrototypeOf() 和函数的 prototype 属性操作实现的。
你写 class B extends A,引擎实际做了三件事:
① 创建构造函数 B;
② 设置 B.prototype.[[Prototype]] = A.prototype(保证实例能访问父类方法);
③ 设置 B.[[Prototype]] = A(让静态方法可继承)。
extends 要求子类必须调用 super(),否则报错 ReferenceError: Must call super constructor
这是因为子类构造函数中,this 在调用 super() 前未被初始化(V8 引擎强制限制)。不调用 super() 就访问 this,会直接抛出该错误。
-
super()必须在子类constructor中**首行之后、任何this访问之前**调用 - 若子类没写
constructor,引擎自动补一个隐式构造函数,并插入super(...args) - 若要修改传给父类的参数,必须显式写
constructor并手动调用super(…)
class Animal {
constructor(name) {
this.name = name;
}
}
class Dog extends Animal {
constructor(name, breed) {
super(name); // ✅ 必须先调
this.breed = breed; // ✅ this 此时已就绪
}
}
static 方法和属性的继承靠的是函数对象自身的 [[Prototype]]
class B extends A 后,B.__proto__ === A 成立(注意:不是 B.prototype.__proto__)。这意味着 A 上定义的 static 方法,能被 B 直接继承调用。
常见误区:以为 static 是挂在 prototype 上——其实它是挂在构造函数自身(即 B 函数对象)上的,而函数对象的隐式原型链指向父类构造函数。
-
A.staticMethod()可被B.staticMethod()调用,因为B.[[Prototype]] === A - 但
B.prototype.staticMethod是undefined,因为static不进prototype - 若重写
B.staticMethod = …,则切断该继承(覆盖),不影响A
想真正理解继承,绕不开 Object.setPrototypeOf() 和 __proto__ 的手动模拟
用 ES5 手动实现 class B extends A,就能看清所有关键连接点:
function A(name) { this.name = name; }
A.prototype.say = function() { return 'hi'; };
function B(name, age) {
A.call(this, name); // ✅ 模拟 super()
this.age = age;
}
// ✅ 模拟 B.prototype.[[Prototype]] = A.prototype
Object.setPrototypeOf(B.prototype, A.prototype);
// ✅ 模拟 B.[[Prototype]] = A(支持 static 继承)
Object.setPrototypeOf(B, A);
上面两行 Object.setPrototypeOf 缺一不可:漏掉第一行,new B().say() 报 undefined;漏掉第二行,B.staticProp 无法从 A 继承。
现代代码里不建议手动改 __proto__ 或反复调用 setPrototypeOf,但调试或写兼容层时,这些才是真实生效的链路节点。











