JavaScript的class本质是构造函数与原型链的语法糖,底层仍基于function和prototype机制,其声明生成不可枚举、不可重写的函数对象,且不被提升。

JavaScript 的 class 本质是语法糖,底层仍基于构造函数和原型链
它不是新增的面向对象机制,而是对已有 function 构造函数 + prototype 模式的封装。写 class 时,JS 引擎会自动把它转成等价的构造函数形式。
class 声明会创建一个不可枚举、不可重写、有 constructor 属性的函数
虽然看起来像“类”,但 class Person 实际生成的是一个特殊函数对象,其 typeof 仍是 "function",且该函数默认不可被 new.target 以外的方式调用(直接调用会报 Class constructor Person cannot be invoked without 'new')。
class Person {
constructor(name) {
this.name = name;
}
}
console.log(typeof Person); // "function"
console.log(Person.prototype.constructor === Person); // true
console.log(Person.name); // "Person"
-
class内部方法默认不可枚举(Object.keys(Person.prototype)不会返回constructor或其他方法) -
class声明不会被提升(ReferenceError),而function声明会被提升 -
class中的constructor必须是函数,且不能是箭头函数或生成器
继承关系完全复用 function 的 prototype 和 __proto__ 链
extends 关键字只是在背后调用 Object.setPrototypeOf(Sub.prototype, Super.prototype) 和 Object.setPrototypeOf(Sub, Super),和手动设置 Sub.prototype = Object.create(Super.prototype) 效果一致。
class Animal {}
class Dog extends Animal {}
// 等价于:
function Animal() {}
function Dog() {}
Object.setPrototypeOf(Dog.prototype, Animal.prototype);
Object.setPrototypeOf(Dog, Animal);
-
super()在子类constructor中必须显式调用,否则无法访问this—— 这是因为子类构造函数中this尚未初始化,而 JS 引擎强制要求由super()触发父类初始化逻辑 -
super.xxx访问父类属性/方法时,this仍指向当前实例,不是父类实例 - 静态方法继承也是靠
Object.setPrototypeOf实现,所以Dog.eat === Animal.eat为false,除非显式赋值
实际编码中容易忽略的关键差异点
这些不是“理论区别”,而是上线后可能引发隐性 bug 的地方:
立即学习“Java免费学习笔记(深入)”;
- 类字段(如
name = 'tom')在构造函数执行前就已初始化,且仅对实例生效;而构造函数内赋值(this.name = 'tom')可依赖参数或异步逻辑 - 类中的方法自动绑定到原型,但类字段声明的箭头函数会绑定到实例,造成内存不共享 —— 和传统构造函数里手写
this.fn = () => {}行为一致 - 私有字段(
#name)不走原型链,也不能被子类访问,哪怕子类也声明同名私有字段,它们也是完全隔离的 - Babel 转译
class时若目标环境不支持class,会降级为function+Object.defineProperty模拟,此时instanceof仍可靠,但某些调试工具可能显示为Function而非class
真正要警惕的,不是“该不该用 class”,而是当调试原型链、动态修改方法、或与老旧库混用时,误以为 class 切断了和函数本质的联系。











