图解JS原型和原型链实现原理
本文深入解析JavaScript原型与原型链的核心设计思想,从语言诞生背景出发,阐明为何采用原型继承而非类继承。详细拆解prototype、constructor与_proto_的关系,通过实例与Object、Function的层级推导,完整展示原型链查找机制,帮助开发者彻底理解JS对象模型。
引言:理解JS继承机制的难点与核心
在初学 JavaScript 的继承机制,特别是原型和原型链时,许多开发者常感到困惑。由于受 Java 继承概念的惯性思维影响,容易在此处产生认知偏差,导致初期只能死记硬背知识点,难以真正领悟其设计初衷。
理解 JS 的继承机制是掌握该语言的核心关键,也是其生命力所在。尽管复杂的继承关系和专业术语常让初学者望而却步,但一旦理清其设计逻辑,便会发现其内在结构其实简洁明了。
在撰写本文前,作者检索了大量关于 JS 原型和原型链的高赞文章,发现多数内容仅停留在概念解释层面,缺乏对继承设计与实现逻辑前后关联性的深入剖析,这使得初学者难以建立完整的知识体系。
学习这一部分的关键在于理解设计者“为什么这样做”,这比单纯掌握“怎么做”更为重要。只有洞察背后的设计动机,才能真正掌握这部分内容。
本文将从设计者的视角出发,对 JS 继承机制进行系统梳理。通过动画演示将复杂的设计思想可视化,并将零散的知识点体系化,旨在帮助读者一次性透彻理解 JS 的继承机制(原型和原型链)。
思维导图

JS的发展史与设计背景
1.JS 的发展史
要深入理解 JS 的核心设计思想,必须追溯其起源。
1.1 为什么会诞生 JavaScript ?
早期较为成熟的浏览器由网景公司发布,那时的浏览器仅能展示网页内容,缺乏用户交互能力。例如,在登录页面输入用户名和密码时,浏览器无法进行本地校验,必须将数据发送至服务器判断,若未输入则返回错误提示。这种设计不仅耗时,还严重浪费服务器资源。

为解决上述问题,网景公司决定开发一种运行在浏览器端的脚本语言,用于执行简单的用户输入校验等操作。
当时最流行的编程语言是面向对象的 Java。为了借助 Java 的影响力推广这种浏览器脚本语言,网景公司将其命名为 JavaScript。尽管名称相似,但两者之间实际上没有任何关系。
1.2 存在的问题
受当时 Java 流行的影响,JS 的数据类型设计倾向于对象类型。这就引出了一个核心问题:既然涉及对象,必然涉及继承机制。那么 JS 的继承机制是模仿 Java 的类继承,还是采用全新的设计思想?
JS继承的设计思想与对象生成
2.JS 继承的设计思想
JS 的开发者思考:如果设计得像 Java 一样拥有“类”的概念,那 JS 就会变成一种完全面向对象的编程语言。最终,开发者决定设计一种独特的继承机制,但其设计思想仍借鉴了 Java 的一些特性。
2.1 生成对象
在 Java 中,通常通过 new 关键字和类来生成实例对象。然而,JS 中没有“类”的概念,设计者该如何实现呢?

开发者找到了 Java 和 JS 的共同点:两者都有构造函数。在 Java 中,new 的过程内部会调用构造函数。由于 JS 没有“类”,设计者将 new 一个“类”的概念转化为 new 一个构造函数,从而使构造函数成为实例对象的原型对象。

原型对象的设计目的与定义
3.为什么要设计原型对象?
上述原型设计存在一个致命缺陷:无法共享公共属性。
因为每 new 一个对象,生成的都是两个不同的实例对象,所以它们的属性也是独立的,无法实现共享。

因此,需要设计一个专门用于存储对象共享属性的对象,称之为「原型对象」。
4.什么是原型对象?
为了让构造函数生成的所有实例对象都能共享属性,我们在构造函数中添加一个名为 prototype 的属性,该属性指向原型对象。我们将所有实例对象共享的属性和方法都放置在这个 prototype 指向的原型对象中,而不需要共享的属性和方法则放在构造函数内部。
这里初学者可能会疑惑:我们知道对象可以设置属性,但函数也可以设置属性吗?对此做简要说明:
JavaScript 中的函数拥有对象的所有能力,因此可以被视为任意其他类型的对象。当我们说函数是“第一类对象”时,意味着函数具备对象的一些功能,例如添加属性和作为参数传递等。
因此,实例对象一旦通过构造函数创建,就会自动继承原型对象上共享的属性或方法。换句话说,该对象的属性都指向了原型对象的属性值。

对象与函数在原型链中的关系
5.对象和函数在原型链关系?

上述图表反映了对象及函数在原型链中的关系。如果读者觉得图表晦涩难懂,无需担心,初学者初学时往往也难以理解。本文将通过逐步拆解来解析这张图,使其变得简单易懂。
文章开头已提及原型对象的概念,简而言之,它就是构造函数的一个 prototype 属性,该属性指向原型对象。
此前我们只讲解了 prototype 属性,下面通过一张图补充剩余的连接属性,只需将这张图铭记于心即可。

分析上图:首先声明一个狗的构造函数,定义其名字和体重属性(私有属性)。如前所述,每个构造函数都有一个 prototype 属性。

这个 prototype 指向原型对象,原型对象中存放的是对象共享的属性。需要注意的是,原型对象中有一个 constructor 属性,该属性指回了构造函数。

我们通过 new 构造函数生成两个狗的对象实例,分别命名为豆豆和贝贝。这两个是不同的对象,名字和体重各不相同,但它们会共享原型对象上的 type 属性,即它们共有的属性都是犬类。

在 JavaScript 的所有对象中,只要存在对象,便具备一个名为 __proto__ 的内置属性。该属性由系统自动生成,一旦创建对象,此属性即随之存在。__proto__ 属性的作用是指向对应的原型对象。
通过上述分步讲解,我们明确了构造函数、对象实例以及原型对象之间的关系。
总结为一句话:
构造函数的 prototype 指向原型对象,原型对象有一个 constructor 属性指回构造函数,每个构造函数生成的实例对象都有一个 _proto_ 属性,该属性指向原型对象。
没错,原型机制就是这么简单。但你会发现问题:原型本身也是对象,而只要是对象都会有一个 _proto_ 属性指向其自身构造函数的原型对象。
确实如此。要确定原型对象的 _proto_ 属性指向谁,就需要知道是哪个构造函数创建了原型对象?
我们知道,所有 JS 对象都继承自一个名为 Object 的对象。可以理解为 Object 构造函数创造了万物,它们的关系如下,道理与前述相同,请仔细理解前文总结的那句话。

但上图中存在一个疑问:Object 构造函数原型对象也是对象,它肯定也有一个 _proto_ 属性,为什么指向 null 呢?
再次引用前文总结:_proto_ 属性指向的是自身构造函数的原型对象。自身的构造函数是谁?是 Object 构造函数。那 Object 构造函数的原型是谁?当然是其本身(如图),因此将 _proto_ 指向了 null。
若不仔细整理,上述关系确实显得杂乱,尤其对初学者而言。但若像本文这样梳理,再复杂的关系也能安排得井井有条。若仍不理解,建议多阅读几篇文章。
原型链的完整解析与总结
6.原型链
还有一个问题未解决:原型链是什么?既然已知什么是原型,那么原型链顾名思义是一条链。既然每个对象都有一个 _proto_ 属性指向原型对象,而原型对象也有 _proto_ 指向其原型对象的原型对象,直到指向上图中的 null,这才到达原型链的顶端。
别忘了,我们尚未完全理解前文那张图。现在我们将图自上而下进行解析。

第一张图的分解:前文所画图的关系与此相同,仔细对比即可发现,第一张图由此解决。

继续向下分割,看第二张图。

第二张图为何如此眼熟?这正是前文分析的 Object 关系图。

第三张图稍微绕弯,但换汤不换药,听我解析。

看起来依然眼熟,只不过将 function 换成了 Function,f 变成了大写的 F。这里涉及一个知识点:在 JS 中,所有 function 函数均由 Function 继承而来,Function 可以说是所有 function 的祖宗。
那 Function 由谁生产?我们看到图中的 Function 函数有 _proto_ 属性,且指向自己的原型对象,这岂不是自己繁衍自己?可以这么理解。
小结
在此纵观全图,总结几条定义,请对照图表查找。
1、所有实例的 _proto_ 都指向该构造函数的原型对象 (prototype)。
2、所有函数(包括构造函数)是 Function 的实例,因此所有函数的 _proto_ 都指向 Function 的原型对象。
3、所有原型对象(包括 Function 的原型对象)都是 Object 的实例,因此 _proto_ 都指向 Object (构造函数) 的原型对象。而 Object 构造函数的 _proto_ 指向 null。
4、Function 构造函数本身是 Function 的实例,因此 _proto_ 指向 Function 的原型对象。
全篇文章的精华在于最后的总结部分,前文的所有分解讲解旨在帮助理解这些函数对象及原型对象之间的关系。这些关系是固定的,谁指向谁都是写死的。只要记住它们的关系,这张图便基本理解透彻。能理解完这张图,你的原型和原型链知识已相当扎实,但仍需通过面试题进行巩固。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持本站。
JS运算符优先级与结合性的区别是什么?
2026-11-05 13:22:02
JS Map怎么只遍历Key或Value
2026-11-05 13:00:36
D3.js 与 ECharts 选型对比:灵活性 vs 开发效率
2026-11-05 09:45:01
为什么JS中typeof []返回object:数组类型检测误区解析
2026-11-04 19:50:47
D3.js 新手入门:环境搭建与第一个条形图实现
2026-11-04 10:49:48
