递归获取对象原型链应使用Object.getPrototypeOf()安全遍历至null终止,避免__proto__和constructor干扰;推荐迭代实现防栈溢出。

要递归获取一个对象的所有原型,核心是沿着 __proto__(或用 Object.getPrototypeOf())向上遍历,直到到达 null 为止。注意避免死循环,尤其在修改过原型链的对象上。
使用 Object.getPrototypeOf 安全遍历
Object.getPrototypeOf() 是标准且推荐的方式,比直接访问 __proto__ 更可靠,兼容性好,也更语义化。
- 每次调用返回当前对象的原型(即它的
[[Prototype]]) - 当到达
Object.prototype时,它的原型是null,这是终点 - 必须手动判断
null终止递归,否则会无限调用
基础递归实现
下面是一个简洁、可读性强的递归函数:
function getPrototypeChain(obj) {
if (obj == null || typeof obj !== 'object') return [];
const proto = Object.getPrototypeOf(obj);
if (proto === null) return [];
return [proto, ...getPrototypeChain(proto)];
}
它返回从直接原型开始、一直到 Object.prototype(不含 null)的原型数组。例如对 new Date() 调用,会依次得到 Date.prototype、Object.prototype。
处理构造函数与 constructor 的干扰
有些对象的 constructor 被改写过,或者原型被重新赋值(比如 Child.prototype = Object.create(Parent.prototype)),但这不影响 Object.getPrototypeOf() 的结果——它只看内部 [[Prototype]],不依赖 constructor 属性。
- 不必检查
obj.constructor.prototype,那是常见误区 - 即使
obj.constructor === Object,只要它是Array实例,它的原型仍是Array.prototype - 真正有效的是
Object.getPrototypeOf(obj),它永远反映真实原型链
补充:迭代版本更稳妥
递归在极深的原型链下可能栈溢出,生产环境建议用迭代:
function getPrototypeChain(obj) {
const chain = [];
let current = obj;
while (current !== null && typeof current === 'object') {
const proto = Object.getPrototypeOf(current);
if (proto === null) break;
chain.push(proto);
current = proto;
}
return chain;
}
逻辑清晰、无调用栈风险,也更容易加入去重或调试日志。


















