类是构造函数的语法糖,本质仍是原型链;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]] 一致。手写继承极易漏掉关键步骤。
立即学习“Java免费学习笔记(深入)”;
常见错误现象:
- 用
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)。
更隐蔽的问题:
- 跨 iframe 的类实例,
instanceof会失效(因为不同全局环境的Array构造函数不是同一个) -
JSON.stringify()会忽略原型上的方法和不可枚举属性,和继承方式无关,但常被误认为“继承没生效” - 用
Reflect.construct动态创建实例时,class必须有new.target检查才能兼容,而普通函数更灵活
复杂点在于:语法看着干净了,但原型链的本质一点没变,出问题时还得翻 __proto__ 和 constructor。










