__proto__ 不是标准API,存在兼容性、跨上下文失效、动态原型篡改失效及忽略Symbol.hasInstance等四大局限;应优先使用Object.getPrototypeOf()等规范方法。

__proto__ 是 JavaScript 中用于访问对象内部 [[Prototype]] 的非标准但广泛支持的属性。它在调试和手动遍历原型链时很直观,但在处理嵌套原型链(比如多层继承、跨上下文对象、动态修改原型)时,存在几个关键局限性。
1. __proto__ 不是标准的遍历接口,行为不一致
虽然大多数引擎支持 obj.__proto__,但它不是 ECMAScript 规范中推荐的正式 API。规范要求使用 Object.getPrototypeOf(obj) 获取原型,而 __proto__ 实际上是部分引擎为兼容性提供的“糖”。不同环境(尤其是旧版 IE、某些 Web Worker 或严格模式下)可能不支持或表现异常。
- 在严格模式中对
__proto__赋值会静默失败或抛错; - 某些嵌入式 JS 引擎(如早期 QuickJS)不暴露
__proto__; - 使用
__proto__修改原型链可能触发引擎优化失效,影响性能。
2. 无法安全处理跨执行上下文的原型链
当对象来自 iframe、Web Worker 或其他全局环境时,其 __proto__ 指向的是那个独立上下文中的原型对象,而非当前全局的 Array.prototype 或 Object.prototype。直接用 === 比较会失败:
-
iframe.contentWindow.Array.prototype !== Array.prototype; - 因此
arr.__proto__ === Array.prototype在跨 frame 场景下恒为false; - 这意味着基于
__proto__手写instanceof或类型判断逻辑,在嵌套窗口结构中不可靠。
3. 对动态原型篡改缺乏防御能力
如果构造函数的 prototype 被中途替换(如 Parent.prototype = {}),而已有实例仍保留旧 __proto__,新旧原型链就分裂了。此时:
立即学习“Java免费学习笔记(深入)”;
- 新创建的实例走新原型链,老实例仍连旧链;
- 用
__proto__遍历时,可能漏掉中间被替换掉的环节; - 无法区分“该对象本应属于某链”和“它实际挂在哪条链上”,导致继承关系误判。
4. 无法反映 Symbol.hasInstance 自定义逻辑
instanceof 运算符底层会调用右侧构造函数的 [Symbol.hasInstance] 方法(如果存在)。而 __proto__ 只反映物理原型链接,完全绕过该钩子:
- 例如:自定义类设置
MyClass[Symbol.hasInstance] = () => true,obj instanceof MyClass返回true; - 但
obj.__proto__ === MyClass.prototype仍为false; - 依赖
__proto__的手写判断会忽略这种语义层面的“实例关系”。
真正稳健的原型链处理,应优先使用 Object.getPrototypeOf() + 循环检查,配合 constructor 和 Symbol.hasInstance 的显式调用,而不是依赖 __proto__ 的直觉式访问。它方便,但不够健壮。


















