彻底搞懂 JavaScript 原型与原型链:proto 和 prototype 到底有什么区别?

写在前面:核心结论速读

如果你时间紧迫,请先记住这 3 点核心区别,带着结论去看正文会更清晰:

  1. 持有者不同prototype 属于构造函数(它是模具);__proto__ 属于实例对象(它是产品)。

  2. 作用不同prototype 是“公共仓库”,用来存放**共用方法;__proto__ 是“线索指针”,用来指向那个仓库。

  3. 一句话总结:开发者通过 prototype 往里存,实例对象通过 __proto__ 往外找

在学习 JavaScript 的过程中,原型(Prototype)和原型链(Prototype Chain)无疑是最容易让人混淆的概念之一。特别是 __proto__prototype 这两个属性,名字相似但作用完全不同。

本文将通过一个通俗易懂的例子,并配合图解,帮助大家彻底厘清这两个概念的关系以及背后的查找机制。

1. 从一个具体的例子开始

为了理解这个概念,我们定义一个简单的构造函数 Pig(猪):

JavaScript

function Pig(name, age, father) {
    this.name = name;
    this.age = age;
    this.father = father;
}

// 往原型对象(公共仓库)里添加方法
Pig.prototype.sleep = function() {
    console.log(this.name + ' 正在睡觉...');
};

// 创建一个实例对象
const peppa = new Pig('Peppa', 5, 'Daddy Pig');

当我们写下这段代码时,JavaScript 引擎在后台建立了关键的连接。我们需要关注两个核心角色:构造函数实例对象

2. 核心关系图解:一张图看懂

在我们深入概念之前,先看这张核心关系图。这是理解一切的基础:

Code snippet

拥有 prototype
拥有 __proto__
拥有 constructor
new 创建
构造函数 Pig
原型对象 Pig.prototype
实例对象 peppa
Pig.prototype 存放公共方法 sleep

从图中我们可以清晰地看到:

  • 左上:构造函数 Pig

  • 中间:公共仓库 Pig.prototype

  • 左下:也就是我们需要关注的实例 peppa

  • 关键点peppaPig 并没有直接的物理连接,它们是通过中间的 Pig.prototype 关联起来的。

3. 核心概念一:prototype(显式原型)

谁拥有它? 只有构造函数(函数)。

在上面的例子中,Pig 是一个构造函数。在声明这个函数时,JavaScript 会自动给它创建一个属性叫做 prototype

它的作用是什么?

prototype 是一个对象,我们可以把它理解为一个公共仓库或者模具。它的主要作用是存储所有 Pig 实例都需要共享的属性和方法。

我的理解总结: prototype 是构造函数特有的,它指向一个对象(原型对象),用来存放公共功能。

4. 核心概念二:proto(隐式原型)

谁拥有它? 所有的对象(包括实例对象)。

当我们使用 new Pig() 创建出 peppa 这个实例时,peppa 身上会自动带有一个属性叫做 __proto__

它的作用是什么?

proto 是一个指针(或线索)。它指向哪里?它指向构造函数的 prototype。

本质上,__proto__ 的存在就是为了让实例对象能够找到它的“出身”,从而访问那个公共仓库里的方法。

JavaScript

// 验证关系
console.log(peppa.__proto__ === Pig.prototype); // true

我的理解总结: 实例对象通过 __proto__ 属性,指向了构造函数的原型对象。

5. 原型链:本质是“查找机制”

当我们理解了上面两个概念,原型链其实就是一个顺着 __proto__ 向上查找的机制。

当我们调用 peppa.sleep() 时,查找过程如下:

Code snippet

没有找到 sleep
找到了! 执行 sleep()
假设还没找到
还没找到
终点
1. 检查 peppa 自身
2. 检查 peppa.__proto__
即 Pig.prototype
3. 检查 Pig.prototype.__proto__
即 Object.prototype
4. 检查 Object.prototype.__proto__
即 null
结束查找
返回 undefined
  1. 第一步(查自己): 引擎首先检查 peppa 实例本身有没有 sleep 属性。

    • 结果:没有(只有 name, age, father)。
  2. 第二步(顺藤摸瓜): 引擎顺着 peppa.__proto__ 找到 Pig.prototype

    • 结果:找到了!
  3. 第三步(执行): 执行该方法。

如果还没找到呢?

如果 Pig.prototype 里也没有这个方法,引擎会继续找 Pig.prototype 的 proto(即 Object.prototype),一直找到 null 为止。这条查找的链路,就叫做原型链。

6. 总结与对比表

为了防止再次混淆,请记住这张对比表:

属性名 prototype proto
持有者 构造函数 (Function) 实例对象 (Object)
形象比喻 公共仓库 / 模具 连接线 / 寻宝地图
核心作用 存放共享的方法和属性 指向原型对象,用于查找方法

最终结论:

  • 构造函数负责建立公共仓库prototype)。

  • 实例对象负责持有线索__proto__)。

  • 原型链负责提供查找机制,确保实例能够通过线索找到仓库中的方法。

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐