JavaScript 的 class 是一个非常精妙的“谎言”。
表面上,它让 JavaScript 看起来像 Java 或 C++ 这种基于类(Class-based)的语言,但其内核依然是那个自由、甚至有些“原始”的原型继承(Prototypical Inheritance)。
要彻底理解它,我们需要撕开这层糖衣,看看底层的内存结构和执行逻辑。
1. 语法糖背后的真相
在 2015 年(ES6)之前,我们通过构造函数来模拟类。class 语法的出现,本质上是将繁琐的原型链操作封装成了更符合人类直觉的关键词。
核心对比
当你写下这段代码时:
JavaScript
class Human {
constructor(name) {
this.name = name;
}
sayHello() {
console.log(`Hi, I'm ${name}`);
}
}
它的底层逻辑等同于:
JavaScript
function Human(name) {
this.name = name;
}
Human.prototype.sayHello = function() {
console.log(`Hi, I'm ${this.name}`);
};
关键差异点:
-
强制性:
class必须配合new使用。如果你直接调用Human(),JavaScript 会报错;而传统的构造函数则会把this绑定到全局对象(非严格模式下),这往往是 Bug 的温床。 -
不可枚举性:
class中定义的方法默认是不可枚举的(non-enumerable),这符合“方法不应出现在for...in循环中”的工程直觉。
2. 深度剖析:new 到底做了什么?
理解 class 的第一步是理解 new 操作符。当我们执行 const me = new Human('Alex') 时,底层发生了四件事:
-
创建一个空对象:
{}。 -
原型关联:将这个空对象的
[[Prototype]](即隐藏属性__proto__)指向Human.prototype。 -
绑定
this并执行:运行constructor里的代码,此时this就指向这个新对象。 -
自动返回:如果构造函数没有返回其他对象,则默认返回这个新创建的对象。
3. 继承的本质:原型链的链接
在 JavaScript 中,继承不是“拷贝”,而是“委托”。
JavaScript
class Developer extends Human {
constructor(name, lang) {
super(name); // 必须先调用 super
this.lang = lang;
}
}
super 的魔法
在 extends 发生时,存在两条原型链的链接:
-
实例原型链:
Developer.prototype.__proto__ === Human.prototype。这保证了Developer的实例可以找到Human的方法。 -
构造函数原型链:
Developer.__proto__ === Human。这保证了Developer可以继承Human的静态方法。
为什么必须先写 super()?
在基于类的语言中,子类实例是先创建的。但在 JS 的 class 继承中,子类的 this 是由父类构造函数生成的。不调用 super(),子类就没有 this。
4. 现代特性:私有属性与内存
JavaScript 最近引入了 # 开头的私有属性(如 #secret)。
JavaScript
class BankAccount {
#balance = 0; // 私有属性
deposit(amount) {
this.#balance += amount;
}
}
底层原理:
不同于 TypeScript 只是在编译时做检查,JS 原生的 # 属性是在 V8 引擎层面实现的。这些属性不在普通的对象键值对中存储,而是存在一个外部的哈希表(WeakMap 结构的变体)中,以对象实例为键。这意味着你无法通过 account['#balance'] 这种黑产手段访问它,实现了真正的封装。
5. 静态成员与块级作用域
-
static关键字:直接定义在构造函数本身上,而不是prototype上。它们属于“类”这个对象,而不属于“实例”。 -
静态初始化块:这是较新的特性,允许你在类定义时执行复杂的初始化逻辑,且能访问私有属性。
总结:如何构建直觉?
你可以把 JS 的 class 想象成一个蓝图工厂:
-
constructor是初始化车间,负责给每个产品打上唯一的标签(属性)。 -
prototype是共享工具库,所有产品共享一套说明书和工具(方法),不占用额外内存。 -
__proto__是寻路指针,当产品发现自己不会某个技能时,通过指针去工具库里找。
底层逻辑永远是:对象链向另一个对象。