JavaScript,如何理解对象的原型链?循环获取原型
发布于 作者:苏南大叔 来源:程序如此灵动~

本文讨论对JavaScript
原型链的更深层次的理解。将从上一篇文章的instanceof
作为引子,展开有关原型链的讨论。看看instanceof
的判断依据是什么。
苏南大叔的“程序如此灵动”博客,记录苏南大叔的代码编程经验总结。本文测试环境:nodejs@20.18.0
,chrome@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
派生出来了两个子类,分别是Man
和Woman
,对应的实例分别是sunan
和xmm
。然而,两者的不同点在于:Man
对其prototype.constructor()
进行了修正。从而导致了instanceof
的判断结果,出现了差异性。
对象sunan
被判定为属于Man
和Person
的实例。而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
获取原型
可以通过下面的方法,获得一个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)); // {}
上面的代码测试结果表明:
- 类实例没有
.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] {} ]
递归获得原型【链】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
经验文章,可以参考:


