JavaScript 的对象模型常常让人一开始觉得“不够直观”。你可能已经见过对象字面量、构造函数、prototype、__proto__、class、extends 这些写法,但如果没有形成一条完整主线,就很容易把它们看成互相独立的知识点。结果就是:会写 class,却说不清它和原型链的关系;会给对象加方法,却不知道为什么有的方法会“从原型上继承”下来。
这一篇要解决的核心问题是:JavaScript 的对象不是靠传统类层级硬性组织起来的,而是建立在原型委托机制之上。class 只是更现代、更易读的语法外衣,底层心智并没有变。把这件事讲清楚,后面你理解框架实例、内建对象、数组方法和很多库的设计时都会轻松很多。
对象在 JavaScript 里到底是什么?
最朴素地说,对象就是一组键值对的集合。但在 JavaScript 里,对象不仅能存数据,还能通过原型链接到另一份对象能力。也就是说,一个对象除了自己拥有的属性外,还可能从它的原型对象那里“沿链路查找”属性和方法。
这和很多传统面向对象语言最大的不同在于,JavaScript 不是先靠类模板定义出固定结构,再实例化;它更像是对象与对象之间建立委托关系。你访问一个属性时,先找对象自己,如果没有,再沿原型链往上找,直到找到或到达链顶。
所以原型链的核心不是“继承语法”,而是“属性查找路径”。
prototype、__proto__、构造函数到底是什么关系?
这是最容易把人绕晕的一组概念。可以先拆开看:
- 函数对象通常有一个
prototype属性,用来放未来实例共享的方法; - 某个对象内部会关联到它的原型对象,历史上很多人通过
__proto__观察这层关系; - 当你用构造函数创建实例时,实例通常会连接到构造函数的
prototype对象。
真正重要的是理解“实例为什么能访问到构造函数原型上的方法”。不是因为它把方法复制了一份,而是因为查找属性时沿原型链找到了那份共享方法。这种机制让多个实例可以复用同一套行为,而不是每次创建对象都生成一份新方法。
为什么说 class 只是语法糖?
现代 JavaScript 为了让对象继承写起来更接近其他语言,引入了 class、constructor、extends、super 这些语法。它们确实让代码更整洁,但底层依然建立在原型和原型链之上。
这意味着,学 class 时不要只学表面写法,还要记住两件事:
- 类方法依然挂在原型上,本质上还是共享行为;
- 继承关系最终仍然表现为原型链委托,而不是另一套完全新的运行机制。
一旦把 class 当成“JavaScript 终于变成传统面向对象语言了”,后面遇到实例属性、静态方法、原型方法、继承覆盖和 this 指向问题时,就很容易理解错位。
原型链解决了什么问题?
它最核心解决的是行为共享。假设你要创建很多相似对象,比如一组用户对象、一组按钮对象、一组表单字段对象,如果每个对象都自己带一套完全相同的方法,会浪费内存,也不利于统一维护。原型链允许你把共享能力放在共同原型上,让实例只保存各自差异化的数据。
从工程角度看,这是一种非常重要的“共享与个性化”平衡方式。实例拥有自己的状态,共享方法由原型统一提供。后面你看数组为什么能直接用 map、filter、push,本质上也是这些方法存在于对应原型链上。
继承是不是 JavaScript 中最重要的复用手段?
未必。很多初学者学到原型链后,会以为 JavaScript 的代码复用核心就是层层继承。实际上,现代前端和 Node 项目里,组合往往比继承更常见、更稳妥。原因很简单:继承层级一深,行为来源和修改影响范围都会变得更难追踪;而组合更容易控制边界和依赖。
所以,理解原型链非常重要,但不等于你要到处用继承。真正需要的是知道 JavaScript 对象模型如何工作,以及什么时候适合利用共享原型、什么时候更应该用组合、工厂函数或模块化来组织逻辑。
这一章在项目里最常见的坑
常见问题通常集中在下面几类:
- 误把实例方法写进构造函数里,导致每个实例都创建一份;
- 只会用
class,但说不清共享方法为什么不在实例自身上; - 修改原型对象时没有意识到会影响所有相关实例;
- 把继承用成主要复用手段,导致层级过深;
- 混淆“对象自有属性”和“沿原型链找到的属性”。
这些问题都提醒我们:对象模型不是为了炫技,而是为了更清楚地组织状态和共享行为。
和后面章节的关系
理解原型链之后,模块、内建对象、DOM 对象、Node API 对象乃至很多框架实例行为,都会更好解释。尤其是当你看到“这个方法为什么每个实例都能调用”“这个属性为什么查得到但自己明明没定义”时,原型链就是最基础的答案。
写在最后
JavaScript 的对象系统不靠传统类层级起家,而是靠原型委托工作。class 带来了更好的可读性,但并没有替换底层机制。学会把“共享行为”“实例状态”“属性查找路径”三件事放在一起理解,你对这门语言的掌控感会强很多。下一篇我们继续进入模块系统,看看 JavaScript 是怎样从单文件脚本走向工程化协作的。