← [ BACK_TO_NOTES ]

JavaScript 原型不是 class

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

#synthesis #growing #dev #javascript #ecmascript

[!info] related notes

JavaScript 原型不是 class

这个概念为什么出现

从 Java/C# 转来的同学看到 class Sku {} 就以为:

  • 实例按类蓝图复制成员
  • 私有/类型系统与运行时一一对应
  • 继承是类型层级的唯一故事

然后在 this、装饰数据、运行时改原型时全面撞墙。

[!abstract] 一句话理解 JS 的属性继承建立在原型委托上;class 使用同一对象模型,同时提供严格模式、构造限制和私有元素等语义。

最小对照示例

场景:价格格式化既要共享方法,又要实例自有币种

// 原型委托:查找时顺着链接走
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 关键字类型定义语法(具体语言规则不同)建立原型关系,并施加构造与方法语义约束

class 不能简单替换为“给 prototype 赋几个函数”:

  • 类体总在严格模式下执行,类构造器必须通过 new 等构造调用进入。
  • 实例方法通常在原型上且不可枚举;公有实例字段是实例自身属性,静态成员在构造函数上。
  • #private 元素有运行时身份检查,不能通过普通属性名访问。
  • Java/C# 通常也共享方法代码;“类语言为每个实例复制方法”本身就是错误前提。

常见误区

[!warning] 常见误区:先背 extends 再理解对象 应先会画 [[Prototype]] 链,再学 class 语法。

工程实践

  • 代码风格可用 class,调试用原型。
  • 需要真正封装时考虑闭包模块、#private 字段,而不是假装 Java。
  • TypeScript 类型层级 ≠ 运行时原型层级的完整替代。

本节总结

用原型链解释属性委托,用 class 规则解释构造、字段与封装;两层都需要理解。

自测题

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

对示例 class B extends A:B 的原型是 A,B.prototype 的原型是 A.prototype,实例的原型是 B.prototype;分别支持静态成员与实例方法的继承。派生构造器还需遵守 super 初始化规则。

创建于 2026/3/15 更新于 2026/10/6
Digital Biome
Access

键盘导航

j / k / ↑ / ↓
选择对象
Enter / o
打开选择
/ 或 Ctrl+K
全站搜索
i / f / 1–4
筛选当前列表
g → h / l / p / t / a
首页 / 笔记 / 项目 / 工具 / About
r → 1–9
打开所选对象的关联
u
返回上一页
Esc
关闭浮层 / 取消命令;输入框内清空文本