类是构造函数的语法糖,本质仍是原型链;class声明不提升、默认严格模式、方法不可枚举;extends比手动继承更安全,自动处理constructor指向、静态方法继承等;子类构造函数中必须先调用super()才能访问this。
类只是构造函数的语法糖,本质没变;继承选 class + extends,但必须理解它背后仍是原型链。
写一个 class Person,和用 function Person() 手动挂方法到 prototype,生成的实例、原型链、instanceof 行为都一样。浏览器和
Node.js 解析 class 时,底层仍转成函数对象。
容易踩的坑:
class 声明不会被提升(ReferenceError),而 function 声明会class 内部默认启用严格模式,无法用 with 或删除不可配置属性class 的方法名是不可枚举的(Object.keys(Person.prototype) 拿不到),而手动赋值的 Person.prototype.method = function(){} 是可枚举的extends 继承比 Object.setPrototypeOf 更安全可靠extends 不仅设置原型链,还自动处理 constructor 指向、静态方法继承、super() 调用检查,并确保子类实例的 __proto__ 和 [[Prototype]] 一致。手写继承极易漏掉关键步骤。
常见错误现象:
Child.prototype = Object.create(Parent.prototype) 后忘了 Child.prototype.constructor = Child,导致 new Child().constructor === Parent
Parent.call(this, ...),父类实例属性丢失Parent.staticMethod 不会自动出现在 Child 上正确做法始终优先用:
class Animal {
constructor(name) {
this.name = name;
}
}
class Dog extends Animal {
constructor(name, breed) {
super(name); // 必须调用
this.breed = breed;
}
}
super() 不是可选语法糖,而是强制执行的初始化逻辑在子类构造函数中,访问 this 前必须调用 super()——这不是风格约定,而是 JS 引擎的硬性限制(否则报 ReferenceError: Must call super constructor)。这是因为子类实例的内存布局依赖父类构造函数初始化。
关键细节:
super() 必须在 this 之前调用,哪怕你只打算返回一个对象字面量super 在方法中指向父类原型,但在构造函数中是特殊语法,不能赋值或 typeof 判断super,它沿作用域链向上找外层函数的 super
instanceof 的隐含成本无论用 class 还是手写,继承链越深,instanceof 和属性查找越慢。现代引擎虽有优化,但超过 4 层继承仍可能触发去优化(deoptimization)。
更隐蔽的问题:
instanceof 会失效(因为不同全局环境的 Array 构造函数不是同一个)JSON.stringify() 会忽略原型上的方法和不可枚举属性,和继承方式无关,但常被误认为“继承没生效”Reflect.construct 动态创建实例时,class 必须有 new.target 检查才能兼容,而普通函数更灵活复杂点在于:语法看着干净了,但原型链的本质一点没变,出问题时还得翻 __proto__ 和 constructor。