前端进阶之旅前端进阶之旅
基础篇
进阶篇
高频篇
精选篇
手写篇
面经篇
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 热点
旧版
首页程序员面试题库JavaScript 原型链属性查找顺序
JavaScript对象与原型

读取一个对象属性时,JavaScript 是按什么顺序在原型链上找的?

读属性时先看对象自己有没有,没有就顺着原型一层层往上找,找到第一个就停下返回;一直找到原型为 null 还没有,结果就是 undefined。

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

一次属性读取经过的三步

  1. 自有属性先查对象自身,有就直接返回,同名的原型属性被遮住
  2. [[Prototype]]自身没有就跳到 Object.getPrototypeOf(obj),重复同样的检查
  3. nullObject.prototype 的原型是 null,走到这里还没找到就是 undefined

查找是每次读取时实时进行的,运行中给原型加属性或改属性,所有继承它的对象下次读取立刻能看到。

核心回答

先记住这个答案

执行 obj.prop 时,引擎先看 obj 自身有没有 prop,有就直接返回。没有就拿到它的原型,也就是 Object.getPrototypeOf(obj),在原型上再找一遍,这样一层层往上,找到第一个同名属性就停。普通对象的链最后是 Object.prototype,它的原型是 null,走到这里还没找到,结果就是 undefined。因为是就近原则,对象自己的属性会遮住原型上的同名属性。

  • 先自身、再原型,找到第一个就停
  • 走到 null 还没找到,返回 undefined
  • 读会沿链往上找,普通赋值只写在对象自身
  • 继承方法里的 this 是调用它的那个对象

看一条三层原型链怎么查

用 Object.create 搭一条三层的链:obj 的原型是 mid,再往上一层是 base,方法只写在 base 上。

找到即停,原型改了立刻生效JavaScript
const base = {
  kind: 'base',
  hello() { return 'I am ' + this.kind }
}
const mid = Object.create(base)
const obj = Object.create(mid)

console.log(obj.hello())
mid.kind = 'mid' // 给中间层加一个同名属性
console.log(obj.hello())
obj.kind = 'obj' // 给对象自身加
console.log(obj.hello(), base.kind)
console.log(obj.missing)
console.log(Object.getPrototypeOf(Object.prototype))
查看输出与解释
I am base
I am mid
I am obj base
undefined
null

第一次调用,obj 和 mid 上都没有 kind,一直找到 base。第二次在 mid 上加了 kind,查找走到 mid 就停了,base 上的不再参与。第三次 obj 自己有了,第一层就命中。base.kind 始终是 'base',遮蔽不会改动原型。 这段代码还说明两件事。一是查找发生在每次读取时,不是创建对象时拷贝一份,所以运行中改原型,下一次读取就能看到。二是 hello 虽然是在 base 上找到的,但里面的 this 指向的是调用它的 obj,所以它读到的 this.kind 也是从 obj 开始查的。这就是为什么所有实例能共用原型上的一份方法,又各自读到自己的数据。

读和写不对称

读属性会沿链往上找,普通赋值不会去改原型上的属性,而是在对象自身上新建一个。上面的 obj.kind = 'obj' 就是这样,base.kind 没变。

但赋值前引擎也会沿原型链看一眼同名属性,有两种情况会改变结果:原型上是一个 setter,或者原型上是只读属性。

原型上有 setter 时,赋值会调用它JavaScript
const proto = {
  set name(v) { this._name = v.trim() }
}
const user = Object.create(proto)

user.name = '  Tom  '
console.log(Object.keys(user).join(','))
console.log(user._name)
console.log(user.name)
查看输出与解释
_name
Tom
undefined

user.name = ... 找到了原型上的 setter,于是调用它,this 是 user,结果 user 身上多了 _name,但没有 name。读 user.name 时找到的还是原型上这个访问器,它只有 set 没有 get,所以读到 undefined。注意查找在这一层就停了,不会因为没有 getter 继续往上找。

原型上的只读属性会挡住赋值
如果原型链上的同名属性是 writable: false,给子对象赋值会失败:严格模式抛 TypeError,非严格模式静默失败,也不会在子对象上新建属性。想绕过只能用 Object.defineProperty 直接在子对象上定义。
回答前,多想一步

容易答错的地方

把 prototype 属性当成对象的原型
构造函数的 prototype 属性,只是 new 创建实例时拿来当实例原型的那个对象。函数自己的原型是 Function.prototype。普通对象根本没有 prototype 属性,要拿原型得用 Object.getPrototypeOf(obj)。
以为 for...in 只遍历自身属性
for...in 会把原型链上可枚举的属性也列出来,和 in 运算符的范围一致。只要自身属性就用 Object.keys,或者在循环里用 Object.hasOwn 过滤。
以为 this 指向找到方法的那一层原型
this 由调用方式决定,obj.hello() 里就是 obj,和方法定义在第几层无关。原型上的 getter 也一样,this 是最开始读属性的那个对象。
试着用自己的话回答

面试官还会怎么问?

怎么判断一个属性是自己的还是继承来的?

Object.hasOwn(obj, 'prop') 只看自身,'prop' in obj 会查整条链。前者为 false 而后者为 true,就说明属性来自原型。

原型链能不能形成环?

不能。用 Object.setPrototypeOf 或给 __proto__ 赋值时,如果新原型会让链绕回自己,引擎直接抛 TypeError,所以查找一定会在 null 处结束。Object.create(null) 创建的对象原型直接就是 null,链只有一层。

原型链太长会不会影响性能?

理论上每多一层就多一次查找,但现代引擎会对属性访问做缓存,结构稳定的短链几乎没有额外开销。真正影响性能的是运行中用 Object.setPrototypeOf 改已有对象的原型,这会让引擎的优化失效,MDN 也明确不推荐这样做。

从一道题,走向一组知识

把知识连起来

对象与原型

怎么判断一个属性是对象自己的,还是从原型上继承来的?

in 会走完整条原型链,hasOwnProperty 只看第一层,正好对应查找过程的两种范围。

对象与原型

给 writable 为 false 的属性赋值,严格模式和非严格模式分别会怎样?

原型链上的只读属性会让子对象的赋值失败,是读写不对称里最容易踩的一个坑。

放回知识体系中复习JavaScript 进阶知识

参考资料

  • Inheritance and the prototype chain

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

本题目录
  1. 先记住这个答案
  2. 看一条三层原型链怎么查
  3. 读和写不对称
  4. 容易答错的地方
  5. 面试官还会怎么问
  6. 把知识连起来
读懂,再试着讲出来

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

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