__proto__ 是非标准但广泛支持的原型访问属性,常见异常包括:在原始值或 null 上访问抛 TypeError;在冻结/不可扩展对象上静默失败或报错;跨 iframe 时原型指向不同 Realm;动态修改导致性能下降和继承链断裂;推荐优先使用 Object.getPrototypeOf() 和 Object.setPrototypeOf()。

__proto__ 属性是 JavaScript 中用于访问对象内部 [[Prototype]] 的非标准但被广泛支持的 getter/setter。它不是语言规范强制要求的接口(ECMAScript 标准推荐使用 Object.getPrototypeOf() 和 Object.setPrototypeOf()),但在实际开发中仍频繁出现。它的异常场景往往不表现为语法错误,而是逻辑错乱、兼容性断裂或静默失效,容易被忽略。
__proto__ 在 null 或原始值上访问会报 TypeError
__proto__ 只能作用于普通对象(包括数组、函数、自定义实例等)。对 null、undefined、数字、字符串、布尔值等原始类型直接读写 __proto__,会触发 TypeError:
-
null.__proto__→TypeError: Cannot read property '__proto__' of null -
"hello".__proto__→TypeError: Cannot read property '__proto__' of string -
42.__proto__→ 语法错误(因点号被解析为小数点),需写成(42).__proto__才能执行,但仍抛TypeError
✅ 正确做法:先确保值是对象类型,可用
typeof x === 'object' && x !== null初筛,再安全访问。
在冻结/不可扩展对象上修改 __proto__ 失败且不报错(静默失败)
当对象被 Object.freeze() 或 Object.preventExtensions() 处理后,尝试设置 obj.__proto__ = newProto:
立即学习“Java免费学习笔记(深入)”;
- 在严格模式下 → 抛
TypeError - 在非严格模式下 → 静默失败(赋值无效,
obj.__proto__保持原值)
这会导致调试困难:代码看似执行成功,实则原型未更新,后续 instanceof 或属性查找失效。
✅ 推荐替代:用
Object.setPrototypeOf(obj, newProto),它在不可变对象上明确抛错,便于定位问题。
跨 iframe 或跨 Realm 场景下 __proto__ 指向不同全局环境的原型
若页面中嵌入 iframe,其内创建的对象(如 iframe.contentWindow.Array)与主窗口的 Array 构造函数无关。此时:
const arr = iframe.contentWindow.Array.from([1]); console.log(arr.__proto__ === Array.prototype); // false console.log(arr instanceof Array); // false
因为 arr.__proto__ 指向的是 iframe 内部的 Array.prototype,而非当前全局的。
✅ 安全判断应优先用
instanceof(注意跨域限制)或Object.prototype.toString.call(arr),避免依赖__proto__值比较。
使用 __proto__ 修改原型链可能破坏继承链或导致性能下降
动态修改 __proto__ 会触发 JS 引擎的“原型链变更”机制,部分引擎(如 V8)会:
- 使对象脱离优化状态(deoptimize)
- 禁用内联缓存(IC),显著拖慢属性访问速度
- 若在循环或高频路径中反复设置,可能引发内存与性能问题
尤其在类继承中误用:
class A { method() { return 'A'; } }
class B extends A {}
const b = new B();
b.__proto__ = {}; // 断开继承,B.prototype 方法不可用
b.method(); // TypeError: b.method is not a function✅ 原型链应在对象创建时确定;运行时变更属反模式,应重构为组合或代理模式。
基本上就这些常见异常场景。__proto__ 不是“不能用”,而是它的副作用隐蔽、边界模糊,现代代码更倾向用标准化 API 替代——既明确语义,又规避陷阱。


















