应优先使用 Reflect.getPrototypeOf(),它是标准、只读、语义明确的反射方法;__proto__ 是非标准、可写、兼容性差的历史属性,仅限临时调试。

__proto__ 和 Reflect.getPrototypeOf() 都能拿到对象的原型,但它们的设计定位、行为规范和适用场景完全不同。
__proto__ 是非标准的历史兼容属性
它最早由浏览器厂商实现,后来为兼容旧代码被写入 ECMAScript 规范附录,但明确标记为“不鼓励使用”。它的本质是对象上的一个访问器属性(getter/setter),直接暴露内部 [[Prototype]]。
- 可读可写:能通过赋值修改原型,但会带来性能损耗和潜在 bug
- 仅限对象:对原始值(如字符串、数字)调用会报错或返回包装对象原型,行为不统一
- 严格模式下赋值静默失败:比如
obj.__proto__ = null不报错也不生效 - 不是所有环境都支持:某些嵌入式 JS 引擎或严格沙箱环境可能禁用它
Reflect.getPrototypeOf() 是标准、安全、一致的反射方法
它是 ES6 Reflect API 的一部分,专为元编程设计,语义清晰、行为确定,且与 Proxy 拦截机制天然协同。
- 只读不可写:纯粹用于查询,无副作用,适合在工具链、调试器、类型检查中稳定使用
- 参数校验严格:传入非对象(null、undefined)直接抛 TypeError,避免隐式转换带来的歧义
- 与 Proxy 兼容:当对象被 Proxy 包裹时,
Reflect.getPrototypeOf(proxy)会正确触发 handler 中的getPrototypeOftrap - 语义明确:名字体现“反射”意图,符合现代 JS 的设计哲学——显式优于隐式
实际开发中怎么选
新项目、库代码、框架底层或需要长期维护的代码,应一律使用 Reflect.getPrototypeOf()。它更可靠,也更容易被静态分析工具识别。
立即学习“Java免费学习笔记(深入)”;
- 如果只是临时调试、快速验证原型链,
obj.__proto__在浏览器控制台里敲起来确实快,但别把它写进正式逻辑 - 需要兼容老旧运行时(如 IE 或某些 IoT 设备)时,可用
Object.getPrototypeOf()作为降级方案,它和Reflect.getPrototypeOf()行为完全一致,只是不属于 Reflect 模块 - 绝对不要用
__proto__做原型链判断或继承检测,比如if (obj.__proto__ === Array.prototype)—— 应改用Array.isArray(obj)或Object.getPrototypeOf(obj) === Array.prototype
补充说明:为什么不用 Object.getPrototypeOf()?
它和 Reflect.getPrototypeOf() 功能完全相同,区别仅在于归属模块:Object 是传统静态工具集合,Reflect 是为反射操作统一设计的命名空间。选择后者更利于代码语义表达和未来扩展(比如配合 Proxy 使用)。


















