原型链遍历本质是沿__proto__或Object.getPrototypeOf()线性向上访问至null,非树形DFS;标准工具函数getPrototypeChain返回从实例到null的完整链,增强版支持stopAt终止、去null及循环检测。

原型链的深度遍历,本质是沿着 __proto__(或 Object.getPrototypeOf())逐层向上访问,直到到达 null。它不是树的 DFS 那种“分支探索”,而是单向、线性的向上追溯——所以更准确地说,是“线性遍历”而非真正意义上的“深度优先遍历”。实现一个健壮的遍历工具,关键在于正确处理循环引用、内置对象边界和不可枚举属性等细节。
明确遍历路径:从实例到 null 的单向链
每个普通对象的原型链终点是 Object.prototype → null。但要注意:
- Function、Array 等内置构造函数的原型链会经过 Function.prototype 或 Array.prototype,最终也归于 Object.prototype;
- 用 Object.create(null) 创建的对象没有 Object.prototype,其原型直接为 null;
- ES6 的 class 语法不改变原型链结构,只是语法糖。
因此,标准遍历只需重复调用 Object.getPrototypeOf(obj),直到返回 null。
基础遍历工具:安全获取完整原型链数组
下面是一个简洁、可复用的工具函数:
function getPrototypeChain(obj) {
if (obj == null || typeof obj !== 'object') return [];
const chain = [];
let current = obj;
while (current !== null) {
chain.push(current);
current = Object.getPrototypeOf(current);
}
return chain;
}使用示例:
const arr = [1, 2]; console.log(getPrototypeChain(arr)); // [Array(2), Array.prototype, Object.prototype, null]
注意:
- 不包含 arr.constructor.prototype(那是 Array.prototype,已自然在链中);
- 返回的数组从实例本身开始,到 null 结束,符合实际继承顺序;
- 对原始值(如字符串字面量)会自动装箱,但建议只对对象调用该函数。
增强版:跳过 null、支持自定义终止条件
真实开发中常需要过滤掉 null,或停在某个特定原型(比如只关心用户自定义部分,忽略 Object.prototype 及之后):
- 用
filter(Boolean)去掉null(因为null是唯一 falsy 的原型) - 添加
stopAt参数,传入期望终止的原型(如Object.prototype),遍历时遇到即停止 - 避免无限循环:检查是否出现重复原型(极少见,但可能出现在手动篡改
__proto__的场景)
function getPrototypeChain(obj, { stopAt, excludeNull = true } = {}) {
if (obj == null || typeof obj !== 'object') return [];
const chain = [];
const seen = new WeakSet();
let current = obj;
while (current !== null) {
if (seen.has(current)) break;
seen.add(current);
if (stopAt && current === stopAt) break;
chain.push(current);
current = Object.getPrototypeOf(current);
}
return excludeNull ? chain : [...chain, current];
}实用技巧:查看原型链上的所有可枚举属性
仅遍历原型链还不够,常需列出每层上的自有属性(含方法)。可用 Object.getOwnPropertyNames() + Object.keys() 组合:
-
Object.getOwnPropertyNames(proto)获取包括不可枚举属性(如toString)的所有键 -
Object.keys(proto)只获取可枚举属性(适合快速查看) - 注意:
for...in会跨原型链遍历且受enumerable控制,不适合精确分析
例如,打印每层原型的自有属性名:
getPrototypeChain([]).forEach((proto, i) => {
if (proto === null) return;
console.log(`Level ${i}:`, Object.getOwnPropertyNames(proto));
});输出中你会看到 Array.prototype 上的 push、map 等,以及 Object.prototype 上的 toString、valueOf —— 这正是 JS 方法查找的实际路径。

















