前端进阶之旅前端进阶之旅
基础篇
进阶篇
高频篇
精选篇
手写篇
面经篇
AI 篇
原理篇
每日一题
小程序题库
知识卡片
  • 场景篇按分类整理的大前端场景考点
  • 历年面经按年份追踪真实考点
  • 算法题库NEW在线编码即时判题
  • 专项自测100 题快速查漏
  • 前端基础
    • HTTP从报文一路讲到 HTTPS
    • 浏览器渲染、事件循环、进程
    • 计算机基础Linux、网络、操作系统
  • 进阶专项
    • 设计模式23 种模式怎么用
    • 前端系统进阶学习大型项目工程化
    • 前端综合文章长期沉淀的实践文
  • 工程与工具
    • Node学习指南从环境搭建到服务端
    • NPM工作流script、依赖与发布
    • Docker容器化部署上手
    • Canvas图形与动画实战
  • 路线与导图
    • 思维导图知识点全景图
    • 学习路线按图索骥不跑偏
  • 动态
    • 公众号动态公众号历史文章
    • 博客动态站长的技术博客
    • 开发者导航常用工具与文档站
  • AI 助手随时提问,即时解析
  • AI 模拟面试模拟真实面试 + 报告
  • AI 知识地图串起全站知识点
  • AI 定制路线按你的简历现排
AI 热点
旧版
基础篇
进阶篇
高频篇
精选篇
手写篇
面经篇
AI 篇
原理篇
每日一题
小程序题库
知识卡片
  • 场景篇按分类整理的大前端场景考点
  • 历年面经按年份追踪真实考点
  • 算法题库NEW在线编码即时判题
  • 专项自测100 题快速查漏
  • 前端基础
    • HTTP从报文一路讲到 HTTPS
    • 浏览器渲染、事件循环、进程
    • 计算机基础Linux、网络、操作系统
  • 进阶专项
    • 设计模式23 种模式怎么用
    • 前端系统进阶学习大型项目工程化
    • 前端综合文章长期沉淀的实践文
  • 工程与工具
    • Node学习指南从环境搭建到服务端
    • NPM工作流script、依赖与发布
    • Docker容器化部署上手
    • Canvas图形与动画实战
  • 路线与导图
    • 思维导图知识点全景图
    • 学习路线按图索骥不跑偏
  • 动态
    • 公众号动态公众号历史文章
    • 博客动态站长的技术博客
    • 开发者导航常用工具与文档站
  • AI 助手随时提问,即时解析
  • AI 模拟面试模拟真实面试 + 报告
  • AI 知识地图串起全站知识点
  • AI 定制路线按你的简历现排
AI 热点
旧版
首页程序员面试题库Object.getPrototypeOf setPrototypeOf 使用与地位
JavaScript对象与原型

Object.getPrototypeOf 和 Object.setPrototypeOf 现在还该用吗?

Object.getPrototypeOf(obj) 是读取原型的标准写法,取代了非标准起家的 __proto__,随便用。Object.setPrototypeOf(obj, proto) 能在运行时换原型,但会让引擎放弃对这个对象的优化,所以应该在创建对象时就用 Object.create 或 class 定好原型。

前端进阶之旅 · 一题精讲更新于 2026.09.29
JavaScript#对象与原型
先看核心答案读代码示例
理解线索

原型的读、写、创建

  1. Object.getPrototypeOf读原型,传原始值会先包装,传 null 或 undefined 抛错
  2. Object.setPrototypeOf运行时改原型,失败时抛 TypeError,成功返回对象本身
  3. Object.create创建对象时直接指定原型,是替代 setPrototypeOf 的首选

性能问题不只影响被改的那个对象。原型被换掉后,所有读过这条原型链的代码,引擎之前做的缓存都可能要作废。

核心回答

先记住这个答案

Object.getPrototypeOf 是读取对象原型的标准 API,ES5 就有了,完全可以放心用,它取代了早期浏览器私自实现的 __proto__。Object.setPrototypeOf 是 ES2015 加的,能在对象创建之后换掉它的原型。它功能上没问题,但 MDN 明确提示这个操作在所有引擎里都很慢,而且影响会波及用到这个对象的所有代码。所以现代写法是创建时就确定原型:用 Object.create(proto)、class extends,或者对象字面量里写 __proto__: proto。

  • 读原型优先用 Object.getPrototypeOf
  • 运行时换原型会拖慢属性访问,能不用就不用
  • 创建时用 Object.create 等确定原型
  • 原型成环会让设置操作抛错

两个 API 的行为

先看它们怎么用、失败时会怎样。

读、写和失败的情况JavaScript
const animal = { eat() { return 'eat' } }
const bird = { fly() { return 'fly' } }

const obj = Object.create(animal) // 推荐:创建时就定好原型
console.log(Object.getPrototypeOf(obj) === animal)

Object.setPrototypeOf(obj, bird) // 运行时换原型,能用但不推荐
console.log(typeof obj.eat, obj.fly())

try {
  Object.setPrototypeOf(bird, obj) // obj 的原型已经是 bird,再让 bird 指向 obj 就成环了
} catch (e) {
  console.log(e.name)
}
console.log(Reflect.setPrototypeOf(Object.freeze({}), bird)) // Reflect 版本不抛错,返回 false
查看输出与解释
true
undefined fly
TypeError
false

换了原型之后,obj 就再也找不到 eat,原来那条原型链整个断开了。原型链不允许成环,引擎会检查并抛 TypeError。冻结或不可扩展的对象也不能换原型,Object.setPrototypeOf 会抛错,而 Reflect.setPrototypeOf 只返回 false,适合在不想写 try 的地方用。

为什么换原型会慢

V8 这类引擎会给对象的「结构」建一个内部描述,叫隐藏类,也叫 shape,记录它有哪些属性、原型是谁。访问属性时,引擎会在调用处缓存「这种结构的对象,属性在什么位置」,下次遇到同样结构的对象直接按缓存取,这叫内联缓存。

原型也是结构的一部分。运行时换原型,这个对象的结构就变了,之前的缓存要作废;如果它本身也是别人的原型,依赖这条链的缓存也要一起作废。引擎还可能对被这样改过的对象放弃一部分优化,之后的属性访问都跟着变慢。所以慢的不是 setPrototypeOf 这一次调用,而是之后的每一次属性访问。

什么时候确实需要它

少数场景没法在创建时定原型。比如继承静态方法:ES5 风格的构造函数想让子类继承父类的静态方法,要写 Object.setPrototypeOf(Child, Parent),Babel 编译 class extends 时也是这样做的。又比如处理第三方给你的对象,你不能控制它的创建过程。这些场景一次性设置、之后不再改,影响可以接受。

要避免的是在热路径上反复修改原型,比如每次请求都给对象换个原型来「切换行为」,这种需求用组合或策略对象来做更合适。

回答前,多想一步

容易答错的地方

以为 __proto__ 是标准推荐写法
obj.__proto__ 访问器是为了兼容老代码才写进规范附录的,只在继承自 Object.prototype 的对象上有效,Object.create(null) 创建的对象就没有。读写原型应该用 Object.getPrototypeOf 和 Object.setPrototypeOf。对象字面量里的 __proto__: proto 是另一回事,它是创建时指定原型的语法,没有性能问题。
以为 getPrototypeOf 返回的是 prototype 属性
Object.getPrototypeOf(fn) 返回的是函数自己的原型,也就是 Function.prototype,不是 fn.prototype。fn.prototype 是给 new fn() 出来的实例用的。
试着用自己的话回答

面试官还会怎么问?

Object.getPrototypeOf('abc') 会报错吗?

ES2015 起不会,原始值先被包装成对象,返回 String.prototype。ES5 里传非对象会抛 TypeError。传 null 或 undefined 现在仍然会抛错。

Object.create(proto) 和 setPrototypeOf({}, proto) 结果一样,为什么推荐前者?

结果看起来一样,但前者是对象一出生结构就确定了,后者是先造了一个原型为 Object.prototype 的对象,再改结构。前者对引擎友好,后者会触发上面说的缓存失效。

怎么判断一个对象是否在另一个对象的原型链上?

用 proto.isPrototypeOf(obj),它会沿着 obj 的原型链一路往上找。如果只关心直接原型,用 Object.getPrototypeOf(obj) === proto。

从一道题,走向一组知识

把知识连起来

对象与原型

class 里的 getter/setter 和普通方法有什么区别?和描述符里的 get/set 是一回事吗?

class 的 getter 定义在原型上,要查它的描述符得先 Object.getPrototypeOf(instance) 拿到原型。

对象与原型

Object.is 和 === 有什么区别?NaN 和 +0、-0 怎么比?

判断原型时写的 Object.getPrototypeOf(a) === B.prototype 是引用比较,可以顺便理清 === 和 Object.is 的区别。

参考资料

  • JavaScript:对象与原型参考资料

示例用于理解所注明的运行环境与边界;延伸学习可结合原文中的更多案例。

本题目录
  1. 先记住这个答案
  2. 两个 API 的行为
  3. 为什么换原型会慢
  4. 什么时候确实需要它
  5. 容易答错的地方
  6. 面试官还会怎么问
  7. 把知识连起来
读懂,再试着讲出来

先看核心答案,再读代码。最后展开追问,检查自己有没有遗漏边界。

试着回答追问
浏览全部面试题理解原理,也关注真实的使用场景。回到顶部 ↑