我们相信:世界是美好的,你是我也是。 来玩一下解压小游戏吧!

本文讨论对JavaScript原型链的更深层次的理解。将从上一篇文章的instanceof作为引子,展开有关原型链的讨论。看看instanceof的判断依据是什么。

苏南大叔:JavaScript,如何理解对象的原型链?循环获取原型 - 对象原型链
JavaScript,如何理解对象的原型链?循环获取原型(图4-1)

苏南大叔的“程序如此灵动”博客,记录苏南大叔的代码编程经验总结。本文测试环境:nodejs@20.18.0chrome@132.0.6834.84。原型链不仅链接了属性及方法,还链接了父子继承关系。

前文回顾

本文的代码基于下面这篇文章:

代码简化:

function Person() {}
function Man() { Person.call(this); }
function Woman() { Person.call(this); }
Man.prototype = Object.create(Person.prototype);
Man.prototype.constructor = Man;
const sunan = new Man();
const xmm = new Woman();

这个代码里面,基于Person派生出来了两个子类,分别是ManWoman,对应的实例分别是sunanxmm。然而,两者的不同点在于:Man对其prototype.constructor()进行了修正。从而导致了instanceof的判断结果,出现了差异性。

对象sunan被判定为属于ManPerson的实例。而xmm被判定为Woman的实例,但是并非Person的实例。这仅仅是因为Man对构造方法进行了修正。

instanceof

instanceof运算符用于检测一个对象是否在其原型链中存在某一个类(名)。

console.log("sunan 是 Man 类的实例吗?", sunan instanceof Man); // true
console.log("sunan 是 Person 类的实例吗?", sunan instanceof Person); // true
console.log("xmm 是 Woman 类的实例吗?", xmm instanceof Woman); // true
console.log("xmm 是 Person 类的实例吗?", xmm instanceof Person); // false

苏南大叔:JavaScript,如何理解对象的原型链?循环获取原型 - 实例判断
JavaScript,如何理解对象的原型链?循环获取原型(图4-2)

获取原型

可以通过下面的方法,获得一个obj的原型(没有链)。

Object.getPrototypeOf(obj)

或者:

obj.__proto__

测试代码:

console.log(sunan.prototype); // undefined
console.log(xmm.prototype); // undefined
console.log(Man.prototype); // Person { constructor: [Function: Man] }
console.log(Woman.prototype); // {}
console.log(Person.prototype); // {}
console.log(sunan.__proto__); // Person { constructor: [Function: Man]
console.log(xmm.__proto__); // {}
console.log(Man.__proto__); // {}
console.log(Woman.__proto__); // {}
console.log(Person.__proto__); // {}
console.log(Object.getPrototypeOf(sunan)); // Person { constructor: [Function: Man]
console.log(Object.getPrototypeOf(xmm)); // {}
console.log(Object.getPrototypeOf(Man)); // {}
console.log(Object.getPrototypeOf(Woman)); // {}
console.log(Object.getPrototypeOf(Person)); // {}

苏南大叔:JavaScript,如何理解对象的原型链?循环获取原型 - 求解__proto__
JavaScript,如何理解对象的原型链?循环获取原型(图4-3)

上面的代码测试结果表明:

  • 类实例没有.prototype,但是有.__proto__内置属性,它指向该对象的原型。
  • 每个类都有一个名为prototype的属性,它是一个对象,包含构造函数的原型对象具有的属性和方法。
  • __proto__属性是指向该对象的原型,等同于Object.getPrototypeOf()
  • prototype属性是用于创建该对象的构造函数的原型。

递归获得原型【链】

JavaScript中,递归地获取一个对象的原型链,通常指的是通过原型链向上追溯到Object.prototype。这个过程可以通过递归地调用Object.getPrototypeOf()方法来实现。这个方法返回指定对象的原型,如果没有继承任何东西,则会返回null

function collectPrototypeChain(obj) {
  const chain = [];
  while (obj !== null) {
      chain.push(obj);
      obj = Object.getPrototypeOf(obj);
  }
  return chain;
}

代码调用:

console.log(collectPrototypeChain(sunan));
console.log(collectPrototypeChain(xmm));

输出:

[
  Man {},
  Person { constructor: [Function: Man] },
  {},
  [Object: null prototype] {}
]

[ Woman {}, {}, [Object: null prototype] {} ]

苏南大叔:JavaScript,如何理解对象的原型链?循环获取原型 - 原型链变数组
JavaScript,如何理解对象的原型链?循环获取原型(图4-4)

递归获得原型【链】2

function printPrototypeChain(obj) {
  if (obj === null) {
      return;
  }
  console.log(obj);
  printPrototypeChain(Object.getPrototypeOf(obj));
}
printPrototypeChain(sunan);
printPrototypeChain(xmm);

输出:

Man {}
Person { constructor: [Function: Man] }
{}
[Object: null prototype] {}

Woman {}
{}
[Object: null prototype] {}

从这个原型链的数组可以看出:instanceof的判断标准,就是来自于__proto__/Object.getPrototypeOf()的层层调用结果的比对。

参考文章

结语

更多苏南大叔的JavaScript经验文章,可以参考:

如果本文对您有帮助,或者节约了您的时间,欢迎打赏瓶饮料,建立下友谊关系。
本博客不欢迎:各种镜像采集行为。请尊重原创文章内容,转载请保留作者链接。

 【福利】 腾讯云最新爆款活动!1核2G云服务器首年50元!

 【源码】本文代码片段及相关软件,请点此获取更多信息

 【绝密】秘籍文章入口,仅传授于有缘之人   js