prototype更安全,因其是构造函数专设的共享模板容器,而__proto__是对象内部原型指针,直接修改会破坏引擎优化、引发兼容问题且被弃用;标准做法应使用Object.setPrototypeOf()等规范API。

操作 prototype 更安全,不是因为它“更不容易出错”,而是因为它的使用场景、语义和规范地位完全不同——prototype 是为构造函数设计的**共享模板容器**,而 __proto__ 是对象内部的**原型指针**,直接修改它会破坏引擎优化、引发兼容性问题,且已被明确不推荐。
prototype 是构造函数的“公共工具箱”
prototype 是函数(尤其是构造函数)的自有属性,专用于定义该函数所有实例共享的方法和属性。它从诞生起就是标准、稳定、可预测的:
- 所有函数默认拥有
prototype,其值是一个普通对象,自带constructor指回自身 - 给
MyClass.prototype.method = ...赋值,只是往一个普通对象上加属性,无副作用 - 实例通过
__proto__自动关联到它,但你无需、也不应直接碰这个链路本身 - 它不改变对象的内部结构,只扩展可被继承的内容,完全符合封装与复用的设计意图
__proto__ 是对象的“内部导航指针”,不该被直接写入
__proto__ 是每个对象都有的内部链接,指向它的原型对象。它本意是供引擎内部使用,而非开发者手动设置:
- 在严格模式下对
obj.__proto__ = x赋值会直接抛出TypeError - IE10 及更早版本、部分嵌入式 JS 引擎(如旧版 IoT 设备运行时)根本不支持该属性
- 频繁修改
__proto__会导致 V8 等引擎放弃内联缓存(IC)和隐藏类优化,显著拖慢属性访问速度 - 语义模糊:它既像数据属性又像访问器,容易让人误以为它是“可自由替换的原型副本”,实际却是影响整个原型链的关键节点
真正该用的标准 API 是 Object.setPrototypeOf()
如果你确实需要动态更改某个对象的原型(例如实现委托、测试或框架底层逻辑),ECMAScript 规范提供的唯一正确方式是:
- 读取原型:
Object.getPrototypeOf(obj) - 设置原型:
Object.setPrototypeOf(obj, newProto) - 创建带指定原型的对象:
Object.create(proto, propertyDescriptors)
这些方法由引擎统一管控:失败时明确报错(比如传入 null 或冻结对象),支持链式调用,且不会干扰 JIT 编译器的内部假设。
混淆根源:prototype 和 __proto__ 不是同一层概念
常见误解是把两者当成“一对可互换的操作”。其实它们分属不同层级:
-
Person.prototype是一个对象(比如{sayHi() {}, species: 'human'}) -
person.__proto__是一个指针,恰好等于Person.prototype—— 它只是“指向”那个对象,不是“就是”那个对象 - 你往
Person.prototype上加东西,所有new Person()实例都能立刻访问;但改person.__proto__,只影响这一个实例,还可能断开原本的继承链

















