原型链大白话详解(含闭环流程图)
原型链就是 JS 实现面向对象继承的核心机制。我会用最通俗的方式拆解,全程无晦涩术语,配合可直接运行的代码,最后给你讲透闭环的形成逻辑 + 完整流程图。
一、先搞懂 2 个核心概念(90% 的人学不懂都是因为搞混了这俩)
先给两个概念做个大白话翻译,再配合例子验证,保证你一次记住:
| 概念 | 大白话定义 | 谁才有? | 核心作用 |
|---|---|---|---|
prototype(原型对象) | 函数自带的公共仓库,一个对象,存着所有实例能共享的属性 / 方法 | 只有函数(尤其是构造函数)才有 | 给 new 出来的所有实例提供共享资源,实现属性 / 方法复用 |
__proto__(原型指针) | 每个对象自带的找爹指针,指向「创造这个对象的构造函数」的prototype | 所有对象(实例、函数、原型对象本身都算对象)都有 | 当对象找不到属性 / 方法时,顺着这个指针往上找,形成原型链的核心 |
举个最直观的例子(和你之前学的 class 完全对应)
// 1. 定义构造函数(等价于class Person)
function Person(name) {
this.name = name; // 实例自身的属性
}
// 2. 给「公共仓库prototype」加共享方法
Person.prototype.sayHi = function() {
console.log(`我是${this.name}`);
};
// 3. new一个实例alice
const alice = new Person('Alice');
// 👇 核心验证(复制到浏览器控制台就能看到结果)
// 实例alice的「找爹指针__proto__」,指向构造函数Person的「公共仓库prototype」
console.log(alice.__proto__ === Person.prototype); // true
// alice自己没有sayHi方法,但能正常执行:顺着__proto__找到了仓库里的方法
alice.sayHi(); // 输出:我是Alice
二、原型链到底是什么?
大白话类比(家谱逻辑)
你可以把原型链理解成 「找东西的家谱路径」:
- 你要找一个东西,先在自己家里找(当前对象自身);
- 自己家没有,就顺着「找爹指针」去你爸的仓库(爹的 prototype)找;
- 你爸的仓库也没有,就去你爷爷的仓库找;
- 一直往上找,直到找到老祖宗的仓库,老祖宗的仓库也没有,就返回
undefined; - 这条从你到祖宗的查找路径,就是原型链。
代码验证基础原型链
接上面的例子,我们顺着指针往上找,看完整的基础链条:
// 1. 第一层:alice自己 → 找不到就去alice.__proto__
// 2. 第二层:alice.__proto__ = Person.prototype → 找不到继续往上
// 3. 第三层:Person.prototype也是个对象,它的__proto__指向谁?
console.log(Person.prototype.__proto__ === Object.prototype); // true
// 4. 第四层:Object.prototype是老祖宗,它的__proto__指向谁?
console.log(Object.prototype.__proto__ === null); // true
所以基础的原型链完整路径是:
alice(实例) → Person.prototype → Object.prototype → null
划重点:
null是原型链的终点,就是为了避免无限循环查找。
三、原型链的闭环是怎么形成的?
很多人搞不懂的「闭环」,核心是 JS 里 Function和Object的特殊关系 ,也是 JS「一切皆对象」的底层逻辑。
先记住 2 个黄金规则(闭环的核心)
- 所有函数,都是
Function构造函数的实例(包括Person、Object、甚至Function自己) - 所有对象,都是
Object构造函数的实例(包括函数的prototype、Function.prototype)
一步步拆解闭环的形成
我们还是用代码验证,每一步都有结果,你可以直接复制运行:
1. 所有构造函数,都是Function的实例
// Person是函数,所以是Function的实例
console.log(Person.__proto__ === Function.prototype); // true
// 连Object构造函数本身,也是函数,所以也是Function的实例
console.log(Object.__proto__ === Function.prototype); // true
// 甚至Function自己,也是函数,所以自己是自己的实例
console.log(Function.__proto__ === Function.prototype); // true
2. 所有原型对象,都是Object的实例
// Function.prototype也是个普通对象,所以是Object的实例
console.log(Function.prototype.__proto__ === Object.prototype); // true
// 之前的Person.prototype,也是Object的实例
console.log(Person.prototype.__proto__ === Object.prototype); // true
3. 闭环最终形成,且有终点不会死循环
把上面的关系连起来,你就看到闭环了:
Object(构造函数)是Function的实例 →Object.__proto__指向Function.prototypeFunction.prototype是Object的实例 →Function.prototype.__proto__指向Object.prototype- 最终
Object.prototype.__proto__指向null,给闭环加了终点,不会无限查找
简单说:Function创造了Object,Object又反过来成为Function的顶层原型,两者互相指向形成闭环,最终汇合到Object.prototype,再到null结束。
四、完整原型链闭环流程图
下面用流程图把所有关系画出来,一眼看懂整个链条和闭环
流程图说明
- 所有函数(包括
Object和Foo)的__proto__都指向Function.prototype:因为函数在 JS 中本质上也是对象,由Function构造而来。 Function.__proto__ === Function.prototype:这是原型链上最神奇的一环(闭环),由引擎底层规定:Function自己也是个函数,属于自身的实例。Function.prototype.__proto__ === Object.prototype:函数的原型本身是一个普通对象,因此它继承自Object.prototype。Object.prototype.__proto__ === null:万物归土,它是原型链的最顶端和终点,再往上就是null。
五、一句话总结
原型链就是对象顺着__proto__指针向上查找属性 / 方法的链式路径,而闭环的本质,是 JS 为了实现「一切皆对象」,让Function和Object互相成为对方的实例,最终所有链条都汇总到Object.prototype,再以null为终点,既形成了完整的继承体系,又避免了无限循环。