ES6 class是原型继承的语法糖,本质仍是构造函数,方法挂prototype,super和extends对应原型操作,完全兼容instanceof。

ES6 class 是原型继承的语法糖,不是新机制,所有“坑”都源于对原型链本质理解不深或误以为 class 改变了底层行为。真正的问题不在语法,而在写法与运行时行为之间的错位。
构造函数调用必须用 new
class 声明自动生成严格模式函数,并插入 _classCallCheck 检查。直接调用 Person("Alice") 会报错,而普通函数不会。这不是 class 的“限制”,而是它强制封装了构造逻辑——但容易忽略:子类 constructor 中没写 super(),也会因 this 未初始化而立即报错。
- 没用 new 调用 class → TypeError: Class constructor Person cannot be invoked without 'new'
- 子类 constructor 第一行没 super() → ReferenceError: Must call super constructor in derived class before accessing 'this' or returning from derived constructor
- super() 必须在第一行,且不能在箭头函数、普通方法中提前调用
实例方法全在 prototype 上,但静态方法挂在构造函数本身
class 写法把 sayHello() 自动挂到 Person.prototype,和 ES5 手写一模一样;但 static create() 直接挂到 Person 函数对象上。这导致两个常见混淆:
- 静态方法无法被实例调用:
new Person().create()报错,必须Person.create() - 继承时,
Child.__proto__ === Parent这条隐式链让静态方法可继承,但很多人误以为是“类继承”,其实只是函数对象的原型链在起作用 - 若手动改写
Child.__proto__ = null,静态方法就断了——说明它真不是魔法,就是普通属性查找
原型链污染与引用类型共享问题依然存在
class 并没有修复原型继承的老问题。比如在父类 prototype 上定义一个数组属性,所有子类实例仍会共享它:
立即学习“Java免费学习笔记(深入)”;
-
class Parent { constructor() { this.items = []; } }—— 每个实例独有,安全 -
Parent.prototype.cache = [];—— 所有实例共用同一数组,push 后互相影响 - extends 后若没重写 constructor,又没调 super,this 不可用,但 prototype 链已建立,方法调用照常走链,容易掩盖初始化错误
instanceof 和原型链强绑定,无法伪造或绕过
判断依据永远是 obj.__proto__ === C.prototype 或其向上追溯。class 只是让这条链更“标准”,但没提供任何隔离手段:
-
new Child() instanceof Parent为 true,因为Child.prototype.__proto__ === Parent.prototype - 用
Object.setPrototypeOf(obj, null)可切断 instanceof 判断,但 class 实例默认不可变原型(严格模式下禁止修改 __proto__) - Symbol.hasInstance 可自定义 instanceof 行为,但 class 不参与该协议,默认仍走原型链
不复杂但容易忽略:所有 class 行为都能用 ES5 构造函数+prototype 手动还原,Babel 编译结果就是铁证。所谓“坑”,其实是把语法糖当成了新范式,而忘了 JS 的根基始终是对象和 [[Prototype]]。


















