普通视图

发现新文章,点击刷新页面。
昨天 — 2025年12月1日首页

JavaScript 原型链:理解对象继承的核心机制

作者 Tzarevich
2025年12月1日 18:07

JavaScript 原型链:理解对象继承的核心机制

在 JavaScript 中,原型链(Prototype Chain) 是实现对象继承和属性查找的核心机制。与传统面向对象语言(如 Java、C++)基于“类”的继承不同,JavaScript 采用的是 基于原型的继承模型。本文将结合 Promise 实例和普通构造函数示例,深入浅出地解析原型链的工作原理。


一、什么是原型链?

每个 JavaScript 对象(除 null 外)内部都有一个隐藏属性 [[Prototype]](可通过 __proto__ 访问),它指向另一个对象——这个对象就是该对象的“原型”。当试图访问一个对象的属性时,如果该对象自身没有这个属性,JavaScript 引擎会沿着原型链向上查找,直到找到该属性或到达原型链的末端(即 null)。

关键点:JavaScript 的继承不是靠“血缘”,而是靠“链条”——原型链。


二、构造函数、原型对象与实例的关系

以自定义构造函数为例:

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

Person.prototype.species = '人';

let zeng = new Person('jw', 18);
  • Person 是一个构造函数。
  • Person.prototype 是一个普通对象,所有通过 new Person() 创建的实例都会以它为原型。
  • zeng.__proto__ === Person.prototype成立
  • Person.prototype.constructor === Person成立

这种结构形成了经典的“三角关系”:

  • 实例(zeng)通过 __proto__ 指向原型对象(Person.prototype
  • 原型对象通过 constructor 指回构造函数(Person

🚂 比喻:可以把 constructor 看作火车头,prototype 是车身,而每个实例是挂在车身后的车厢。它们通过“挂钩”(__proto__)连接在一起。


三、动态修改原型:打破常规

JavaScript 的原型是可变的。我们可以随时修改对象的 __proto__

const kong = {
  name: 'kong',
  hobbies: ['篮球', '足球'],
};

zeng.__proto__ = kong;
console.log(zeng.hobbies); // ['篮球', '足球']
console.log(zeng.species); // undefined

此时:

  • zeng 不再从 Person.prototype 继承属性;
  • 而是从 kong 对象继承;
  • 因此 species 找不到了,但 hobbies 可以访问。

⚠️ 注意:虽然技术上可行,但不推荐随意修改 __proto__ ,因为它会破坏性能优化,并可能导致代码难以维护。


四、内置对象也遵循原型链:以 Promise 为例

ES6 引入的 Promise 同样遵循原型链规则:

const p = new Promise((resolve, reject) => {
  setTimeout(() => reject('失败1'), 3000);
});
  • p 是一个 Promise 实例;
  • p.__proto__ === Promise.prototypetrue
  • Promise.prototype 上定义了 .then(), .catch(), .finally() 等方法;
  • 所以 p.then(...) 实际上调用的是 Promise.prototype.then

执行流程:

  1. new Promise(...) 立即执行 executor 函数(同步)→ 输出 '111'
  2. 主线程继续执行 → 输出 '222'p 的初始状态(pending)
  3. 3 秒后,reject('失败1') 触发状态变为 rejected
  4. 微任务队列中安排 .catch() 回调 → 输出 '失败1'
  5. .finally() 总是执行 → 输出 'finally'

这再次印证:所有对象的行为都依赖于其原型链上的方法


五、原型链的本质:属性查找机制

当你写 obj.method() 时,JavaScript 引擎会:

  1. obj 自身查找 method
  2. 若无,则查找 obj.__proto__
  3. 若仍无,继续查找 obj.__proto__.__proto__
  4. ……直到 Object.prototype(最顶层)
  5. 若最终找不到,返回 undefined

例如:

zeng.toString(); // 虽然 zeng 自身没有 toString,但 Object.prototype 有

因为:

zeng 
→ __proto__ = kong 
→ __proto__ = Object.prototype 
→ has toString()

六、总结

概念 说明
__proto__ 实例指向其原型的链接(非标准但广泛支持)
prototype 构造函数的属性,用于被实例的 __proto__ 引用
constructor 原型对象上的属性,指回构造函数
原型链 属性/方法查找的路径,从实例 → 原型 → 原型的原型 → … → null

JavaScript 的面向对象不是靠“类继承”,而是靠“对象委托”——你没有的,我帮你问我的原型要。这种灵活而强大的机制,正是 JavaScript 动态特性的基石。

✅ 牢记:一切皆对象,万物皆可链。理解原型链,就掌握了 JavaScript 面向对象的灵魂。

❌
❌