隐式原型(__proto__)是对象内部[[Prototype]]指针的非标准访问器,而Object.getPrototypeOf()等API是规范定义的受控内存操作接口;前者直接暴露底层指针,后者具备类型校验、安全读写与引擎优化支持。

隐式原型(__proto__)和标准操作 API(如 Object.getPrototypeOf()、Object.setPrototypeOf()、Object.create())在内存模型中不是并列概念,而是“底层机制”与“规范接口”的关系:前者是对象内部的原型指针实现,后者是 JS 引擎为安全、可控地访问或修改该指针所提供的标准化内存操作入口。
隐式原型是对象的内部原型指针
每个 JavaScript 对象在内存中都持有一个内部属性 [[Prototype]],它是一个指向另一个对象的引用(即原型对象)。浏览器用 __proto__ 作为非标准但广泛支持的访问器暴露该指针。它不是存储在对象自身属性中,而是由引擎在对象创建时自动设置,指向其构造函数的 prototype 对象(如 new Foo() 的实例,其 [[Prototype]] 指向 Foo.prototype)。
- 该指针存在于对象的内存布局中,属于对象的“元数据”部分,不参与属性枚举
- 它的值在对象生命周期内可被修改(例如通过
obj.__proto__ = otherObj),但直接赋值会触发引擎内部的原型链重链接操作 - 修改
__proto__会影响整个原型链的查找路径,进而改变属性/方法的动态解析行为
标准 API 是对 [[Prototype]] 的受控内存操作
Object.getPrototypeOf() 和 Object.setPrototypeOf() 不是对 __proto__ 的简单封装,而是规范定义的、具备语义约束和运行时检查的内存操作原语:
-
Object.getPrototypeOf(obj)安全读取对象的 [[Prototype]] 值,不触发 getter/setter,且对 null/undefined 有明确定义行为 -
Object.setPrototypeOf(obj, proto)在设置前校验proto是否为对象或 null;若非法则抛出 TypeError,避免内存状态损坏 -
Object.create(proto, propertiesObject)直接在堆上分配新对象,并原子性地初始化其 [[Prototype]] 字段,绕过构造函数流程,是创建“纯净原型链”的底层手段
内存模型视角下的关键差异
从 V8 或 SpiderMonkey 等引擎的内存实现看:
-
__proto__的赋值可能引发隐藏类(hidden class)去优化(deoptimization),因为原型变更会破坏内联缓存(IC)假设,导致后续属性访问回退到慢路径 - 标准 API 调用会进入引擎的 native 方法层,执行更严格的类型检查与写屏障(write barrier),确保垃圾回收器能正确追踪原型链引用关系
- 使用
Object.setPrototypeOf()修改原型比直接改__proto__更易被 JIT 编译器识别为“有意图的原型变更”,从而保留部分优化机会
实际开发中的内存意识建议
避免在热路径中频繁变更原型链,因其代价远超普通属性操作:
- 优先用
Object.create(null)创建无原型对象(如 Map 替代品),减少原型链查找开销 - 若需共享方法,用组合代替原型继承,避免深层原型链带来的内存间接寻址成本
- 调试时可用
Object.getPrototypeOf()安全遍历链,而非依赖__proto__——后者在严格模式下可能不可写,且某些环境(如 React Native 旧版)会屏蔽

















