JavaScript 原型不是 class
对照经典类继承与原型委托,说明 class 语法糖的边界,避免把 Java/C# 心智硬套到 JS。
#type / synthesis
#status / growing
#tech / dev
#resource / javascript
#resource / ecmascript
[!info] 关联笔记
- 所属:类型与对象模型 MOC
- 前置:原型链 · class
- 相关:ES6/ES5 继承对照
JavaScript 原型不是 class
这个概念为什么出现
从 Java/C# 转来的同学看到 class Sku {} 就以为:
- 实例按类蓝图复制成员
- 私有/类型系统与运行时一一对应
- 继承是类型层级的唯一故事
然后在 this、装饰数据、运行时改原型时全面撞墙。
[!abstract] 一句话理解 JS 的对象系统是原型委托;
class是更友好的语法,不把语言变成 Java。
最小对照示例
场景:价格格式化既要共享方法,又要实例自有币种
// 原型委托:查找时顺着链接走
const pricing = {
currency: 'CNY',
format(amount) {
return amount + ' ' + this.currency
},
}
const skuPricing = Object.create(pricing)
skuPricing.currency = 'USD' // 写在自身,不影响原型默认
console.log(skuPricing.format(12)) // 12 USD
console.log(pricing.format(12)) // 12 CNY
// class 语法仍然生成原型关系
class Pricing {
constructor(currency) {
this.currency = currency
}
format(amount) {
return amount + ' ' + this.currency
}
}
class SkuPricing extends Pricing {}
const p = new SkuPricing('EUR')
console.log(Object.getPrototypeOf(p) === SkuPricing.prototype)
console.log(Object.getPrototypeOf(SkuPricing.prototype) === Pricing.prototype)
核心对照
| 维度 | 经典类语言直觉 | JavaScript |
|---|---|---|
| 方法存放 | 类上的成员定义 | 通常在原型上共享 |
| 继承 | 类型系统 + 布局 | 对象链接委托 |
| 扩展 | 编译期类型 | 运行时也可改对象形状 |
| class 关键字 | 核心模型 | 语法糖 + 一些语义约束 |
常见误区
[!warning] 常见误区:先背 extends 再理解对象 应先会画
[[Prototype]]链,再学 class 语法。
工程实践
- 代码风格可用 class,调试用原型。
- 需要真正封装时考虑闭包模块、
#private字段,而不是假装 Java。 - TypeScript 类型层级 ≠ 运行时原型层级的完整替代。
本节总结
把 JS 当原型语言,class 是皮;把 JS 当 Java,运行时处处是刺。
自测题
extends在运行时主要建立了什么?
参考答案
构造函数与原型对象之间的原型链接关系(以及部分静态继承),不是编译期类表复制。