__proto__不是JavaScript标准属性,而是Firefox早期私有实现、因兼容性被保留的遗留特性;应使用Object.getPrototypeOf()、Object.setPrototypeOf()和Object.create()等标准方法替代。

__proto__ 不是标准属性,而是浏览器早期私有实现的遗留产物,因历史兼容性被保留至今。它从未进入 ECMAScript 主规范,ES6 明确将其划入附录 B——仅限浏览器、非强制实现的“历史特性”。但它又被广泛使用,是因为它直观、易写、在主流浏览器中长期可用,很多教程和旧代码都依赖它,形成了事实上的惯性。
它从哪里来?不是标准,却“活”了下来
Firefox 最早在 2000 年代初引入 __proto__,用于直接暴露对象内部的 [[Prototype]] 槽。其他浏览器为兼容已有脚本,陆续跟进支持。ECMAScript 5(2009)已提供标准替代方案,但为了不破坏海量线上代码,引擎选择继续保留 __proto__ 的可读写能力——这不是认可它,而是妥协。
为什么不该在新项目中用它?
- Node.js 等非浏览器环境不保证支持,某些配置下甚至被禁用
- 严格模式下对
__proto__赋值可能直接抛错 - V8 等引擎对其写操作有性能惩罚,影响优化编译
- 容易与
prototype混淆:前者属于对象,后者属于函数,语义完全不同 - 它只是访问器属性,底层行为由引擎自行实现,跨环境表现不一致
标准替代方案怎么用?
所有操作都围绕规范定义的内部槽 [[Prototype]],语义清晰、环境一致:
- 读原型:
Object.getPrototypeOf(obj)替代obj.__proto__ - 设原型:
Object.setPrototypeOf(obj, proto)替代obj.__proto__ = proto - 创建对象:
Object.create(proto, descriptors)替代{ __proto__: proto }(后者仅在字面量中被语法接纳,不可用于已有对象) - 安全克隆:
Object.create(Object.getPrototypeOf(obj), Object.getOwnPropertyDescriptors(obj))
唯一被宽松接受的例外
对象字面量中的 { __proto__: proto } 是 ES6 正式承认的简写语法,等价于 Object.create(proto)。但这不改变 __proto__ 本身是非标准属性的事实——它只是该特定语法位置的特例,不能用于读/写已有对象的原型。

















