← 返回目录

第 6 卷

第 6 / 19 卷日期:

原型链是由对象的 [[Prototype]] 属性串联起来的链式结构,是JavaScript实现属性查找和继承的核心机制:

  1. 当访问一个对象的某个属性或方法时,JavaScript引擎会先在该对象自身的属性中查找;
  2. 若查找不到,则会沿着该对象的 [[Prototype]] 属性,查找其原型对象的属性;
  3. 若原型对象中仍查找不到,则继续沿着原型对象的 [[Prototype]] 属性,查找原型的原型;
  4. 以此类推,直到找到该属性/方法,或到达原型链的终点( null);
  5. 若到达终点仍未找到,则返回 undefined(属性)或抛出 TypeError(方法)。

示例(原型链查找):

Code block

1// p1的原型链:p1 -> Person.prototype -> Object.prototype -> null
2console.log(p1.toString());// [object Object]
3//查找过程:
4// 1. p1自身没有toString方法
5// 2.查找p1.__proto__(Person.prototype),也没有toString方法
6// 3.查找Person.prototype.__proto__(Object.prototype),找到toString方法
7// 4.执行该方法

8 9console.log(p1.xxx); // undefined

10// 查找过程:

11// 1. p1自身无xxx 12// 2. Person.prototype无xxx

13// 3. Object.prototype无xxx 14// 4. 原型链终点null,返回undefined

  1. 为什么JavaScript需要存在原型和原型链,它设计的目的是什么?

JavaScript设计原型和原型链的核心目的是实现对象的继承和属性方法的共享,同时兼顾内存效率和灵活性,具体原因如下:

  1. 实现属性和方法的共享,节省内存空间

◦ 若没有原型机制,每个对象实例都需要单独定义其方法和共享属性,这会导致大量重复代码,

占用过多内存。

◦ 原型机制允许将所有实例共享的方法和属性定义在构造函数的 prototype(原型对象)上,

所有实例通过 [[Prototype]] 引用该原型对象,实现共享,大幅节省内存。

◦ 示例:所有 Person 实例共享 sayHello 方法,无需为每个实例创建独立的 sayHello 函

◦ JavaScript没有类(ES6的 class 是语法糖,底层仍基于原型),原型链是实现对象继承的唯

一方式。

◦ 通过将一个对象的原型指向另一个对象,即可让前者继承后者的所有属性和方法;通过原型链

的多层串联,可实现多层继承,构建复杂的对象关系。

◦ 示例: Person.prototype 的原型指向 Object.prototype,因此 Person 实例继承

了 Object 的所有内置方法( toString、 hasOwnProperty 等)。

  1. 提供灵活的对象扩展能力

◦ 原型链是动态的:若在原型对象上新增属性或方法,所有继承该原型的实例对象(无论创建于

原型修改前还是修改后)都能立即访问到该新增内容,无需重新创建实例。

◦ 这种动态扩展能力让JavaScript对象更加灵活,可随时调整对象的行为,适应复杂的开发场

景。

Code block

1// 给Person.prototype新增方法

2Person.prototype.getAge = function() {
3return this.age;
4};
5p1.age = 20;
6console.log(p1.getAge());// 20(已创建的p1实例可直接访问新增方法)
  1. 简化对象创建和复用逻辑

◦ 原型机制允许基于已有对象快速创建新对象(如 Object.create(proto)),无需定义复

杂的类结构,简化了对象的创建流程。

  • 同时,通过原型链的继承关系,可复用已有对象的功能,减少重复开发,提升开发效率。

15. 原型链的终点是什么,以及如何在代码中打印出一个对象的原型链直

至其终点?

(1)原型链的终点

JavaScript原型链的终点是 null。

具体说明:

  1. 所有对象的原型链最终都会追溯到 Object.prototype(Object的原型对象);

2.Object.prototype 的 [[Prototype]](隐式原型)指向 null,即

1console.log(Object.getPrototypeOf(Object.prototype));// null
2const obj = {};
3// obj的原型链:obj -> Object.prototype -> null
4console.log(obj.__proto__ === Object.prototype);// true
5console.log(obj.__proto__.__proto__ === null);// true

(2)代码打印对象的原型链直至终点

有两种常用方式可以打印对象的完整原型链,直至 null:

方式1:循环遍历 + Object.getPrototypeOf(推荐,标准API)

Code block

1/** 2* 打印对象的完整原型链

3* @param{Object} obj-要打印原型链的对象
4*/
5function printPrototypeChain(obj) {
6let currentObj = obj;
7console.log(`===== ${obj.constructor.name || "对象"}的原型链=====`);
8//循环遍历,直到currentObj为null
9while (currentObj !== null) {
10//打印当前对象的构造函数名称(便于识别)
11const constructorName = currentObj.constructor ?

currentObj.constructor.name : "未知对象";

12console.log(currentObj);

13console.log(`构造函数:${constructorName}`);
14//获取下一个原型对象
15currentObj = Object.getPrototypeOf(currentObj);
16//分隔线
17if (currentObj !== null) {
18console.log("↓");
19}
20}
21console.log("=====原型链终点(null)=====");
22}
24//测试示例
25function Person(name) {
全站分卷索引 · 19 卷
  1. 1第 1 卷
  2. 2第 2 卷
  3. 3第 3 卷
  4. 4第 4 卷
  5. 5第 5 卷
  6. 6第 6 卷
  7. 7第 7 卷
  8. 8第 8 卷
  9. 9第 9 卷
  10. 10第 10 卷
  11. 11第 11 卷
  12. 12第 12 卷
  13. 13第 13 卷
  14. 14第 14 卷
  15. 15第 15 卷
  16. 16第 16 卷
  17. 17第 17 卷
  18. 18第 18 卷
  19. 19第 19 卷