JavaScript 原型不是 class

对照经典类继承与原型委托,说明 class 语法糖的边界,避免把 Java/C# 心智硬套到 JS。

#type / synthesis #status / growing #tech / dev #resource / javascript #resource / ecmascript

[!info] 关联笔记

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,运行时处处是刺。

自测题

  1. extends 在运行时主要建立了什么?
参考答案

构造函数与原型对象之间的原型链接关系(以及部分静态继承),不是编译期类表复制。

创建于 2026/3/15 更新于 2026/7/15