__proto__未被删除,而是被标记为历史遗留、不推荐使用;Object.getPrototypeOf()和Object.setPrototypeOf()是标准、安全、可预测的替代方案。

“__proto__之死”不是它真的被删除了,而是它被明确标记为**历史遗留、不推荐使用**的内部属性;而 Object.getPrototypeOf() 和 Object.setPrototypeOf() 是标准、安全、可预测的替代方案——理清这点,就抓住了现代 JavaScript 原型操作的核心转向。
__proto__ 为什么“该退场”?
它本质是 [[Prototype]] 内部槽位的一个非标准访问器(getter/setter),早期浏览器实现时暴露给了开发者,但规范从未将其定义为公共 API。它的主要问题包括:
- 语义模糊:名字带双下划线,看起来像私有,实际却广泛可用,造成误解
- 性能隐患:直接修改
__proto__可能导致 JS 引擎放弃对对象的优化(如隐藏类失效) - 不可靠性:在某些严格模式或特殊环境(如 Web Workers、某些 polyfill 场景)中行为不一致
- 与
prototype持续混淆:一个属于实例,一个属于函数,但命名毫无区分度
getPrototypeOf:读取原型的唯一推荐方式
Object.getPrototypeOf(obj) 是获取对象 [[Prototype]] 的标准方法,返回值总是确定且不可变的(返回的是原型对象本身,不是引用副本)。
- 它不依赖对象是否由构造函数创建——
Object.create(null)、字面量{}、数组[]、正则/a/都能正确返回其原型 - 它不会触发任何副作用,纯函数式,适合调试和类型判断(比如
Object.getPrototypeOf([]) === Array.prototype) - 对比:
obj.__proto__在某些冻结对象或 Proxy 上可能报错或返回意外结果,而getPrototypeOf始终稳定
setPrototypeOf:谨慎使用的“写入权”
Object.setPrototypeOf(obj, prototype) 是设置原型的标准入口,但它不是“自由嫁接”的工具——它有明确限制和代价:
立即学习“Java免费学习笔记(深入)”;
- 只能将
prototype设为对象或null;传入原始值(如42、"str")会静默转为对应包装对象的原型,容易出错 - 频繁调用会显著拖慢后续属性访问速度,因为引擎需重建对象的内联缓存(IC)
- 实践中,应只在初始化阶段(如
Object.create()替代方案)或极少数需要动态委托的场景使用,而非运行时反复切换 - 注意:它不能改变
Function、Array等内置构造函数实例的原型链顶端(如无法让数组继承自Map.prototype),这是引擎硬性保护
真正替代 __proto__ 的完整链条
不只靠两个 API,而是一套协同机制:
- 创建时指定原型 → 用
Object.create(proto, descriptors)或class extends - 读取原型 → 统一用
Object.getPrototypeOf(obj) - 写入原型 → 优先用
Object.setPrototypeOf(obj, proto),禁用obj.__proto__ = ... - 检查继承关系 → 用
obj instanceof Constructor或Constructor.prototype.isPrototypeOf(obj),而非比对__proto__链 - Proxy 中拦截 →
getPrototypeOf和setPrototypeOftrap 直接对应 Reflect 方法,完全绕过__proto__


















