原型链大白话详解

2 阅读4分钟

原型链大白话详解(含闭环流程图)

原型链就是 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

二、原型链到底是什么?

大白话类比(家谱逻辑)

你可以把原型链理解成 「找东西的家谱路径」

  1. 你要找一个东西,先在自己家里找(当前对象自身);
  2. 自己家没有,就顺着「找爹指针」去你爸的仓库(爹的 prototype)找;
  3. 你爸的仓库也没有,就去你爷爷的仓库找;
  4. 一直往上找,直到找到老祖宗的仓库,老祖宗的仓库也没有,就返回undefined
  5. 这条从你到祖宗的查找路径,就是原型链

代码验证基础原型链

接上面的例子,我们顺着指针往上找,看完整的基础链条:

    // 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.prototypeObject.prototypenull

划重点:null是原型链的终点,就是为了避免无限循环查找。


三、原型链的闭环是怎么形成的?

很多人搞不懂的「闭环」,核心是 JS 里 FunctionObject的特殊关系 ,也是 JS「一切皆对象」的底层逻辑。

先记住 2 个黄金规则(闭环的核心)

  1. 所有函数,都是Function构造函数的实例(包括PersonObject、甚至Function自己)
  2. 所有对象,都是Object构造函数的实例(包括函数的prototypeFunction.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.prototype
  • Function.prototypeObject的实例 → Function.prototype.__proto__指向Object.prototype
  • 最终Object.prototype.__proto__指向null,给闭环加了终点,不会无限查找

简单说:Function创造了ObjectObject又反过来成为Function的顶层原型,两者互相指向形成闭环,最终汇合到Object.prototype,再到null结束。


四、完整原型链闭环流程图

下面用流程图把所有关系画出来,一眼看懂整个链条和闭环

image.png

流程图说明

  1. 所有函数(包括 ObjectFoo)的 __proto__ 都指向 Function.prototype:因为函数在 JS 中本质上也是对象,由 Function 构造而来。
  2. Function.__proto__ === Function.prototype:这是原型链上最神奇的一环(闭环),由引擎底层规定:Function 自己也是个函数,属于自身的实例。
  3. Function.prototype.__proto__ === Object.prototype:函数的原型本身是一个普通对象,因此它继承自 Object.prototype
  4. Object.prototype.__proto__ === null:万物归土,它是原型链的最顶端和终点,再往上就是 null

五、一句话总结

原型链就是对象顺着__proto__指针向上查找属性 / 方法的链式路径,而闭环的本质,是 JS 为了实现「一切皆对象」,让FunctionObject互相成为对方的实例,最终所有链条都汇总到Object.prototype,再以null为终点,既形成了完整的继承体系,又避免了无限循环。