前端进阶之旅前端进阶之旅
  • 基础篇HTML/CSS/JS 打底
  • 进阶篇原理与工程化
  • 高频篇面试最常问的那批
  • 精选篇按模块收敛的总结
  • 手写篇常考代码手写实现
  • 面经篇真实面试问题复盘
  • AI 篇NEWAI 时代的前端考点
  • 历年面经NEW按年份追踪真实考点
  • 每日一题每天一道,攒手感
  • 专项自测100 题快速查漏
  • 小程序题库小程序专项刷题
  • 算法题库NEW在线编码即时判题
  • 知识卡片NEW碎片时间过考点
  • 面试题大全常见问题解析
  • AI 答疑NEW随时提问,即时解析
  • AI 模拟面试NEW模拟真实面试 + 报告
  • AI 定制路线NEW按你的简历现排
  • AI 知识地图NEW串起全站知识点
  • 原理篇React / Vue 源码拆解
  • HTTP从报文一路讲到 HTTPS
  • 浏览器渲染、事件循环、进程
  • 计算机基础Linux、网络、操作系统
  • 设计模式23 种模式怎么用
  • Node学习指南从环境搭建到服务端
  • NPM工作流script、依赖与发布
  • Docker容器化部署上手
  • Canvas图形与动画实战
  • 前端系统进阶学习大型项目工程化
  • 前端综合文章长期沉淀的实践文
  • 思维导图知识点全景图
  • 学习路线按图索骥不跑偏
  • AI 热点NEWAI 每日动态
  • 公众号动态公众号历史文章
  • 博客动态站长的技术博客
  • 开发者导航常用工具与文档站
  • 基础篇HTML/CSS/JS 打底
  • 进阶篇原理与工程化
  • 高频篇面试最常问的那批
  • 精选篇按模块收敛的总结
  • 手写篇常考代码手写实现
  • 面经篇真实面试问题复盘
  • AI 篇NEWAI 时代的前端考点
  • 历年面经NEW按年份追踪真实考点
  • 每日一题每天一道,攒手感
  • 专项自测100 题快速查漏
  • 小程序题库小程序专项刷题
  • 算法题库NEW在线编码即时判题
  • 知识卡片NEW碎片时间过考点
  • 面试题大全常见问题解析
  • AI 答疑NEW随时提问,即时解析
  • AI 模拟面试NEW模拟真实面试 + 报告
  • AI 定制路线NEW按你的简历现排
  • AI 知识地图NEW串起全站知识点
  • 原理篇React / Vue 源码拆解
  • HTTP从报文一路讲到 HTTPS
  • 浏览器渲染、事件循环、进程
  • 计算机基础Linux、网络、操作系统
  • 设计模式23 种模式怎么用
  • Node学习指南从环境搭建到服务端
  • NPM工作流script、依赖与发布
  • Docker容器化部署上手
  • Canvas图形与动画实战
  • 前端系统进阶学习大型项目工程化
  • 前端综合文章长期沉淀的实践文
  • 思维导图知识点全景图
  • 学习路线按图索骥不跑偏
  • AI 热点NEWAI 每日动态
  • 公众号动态公众号历史文章
  • 博客动态站长的技术博客
  • 开发者导航常用工具与文档站
首页程序员面试题库hasOwnProperty 与 in 区分自身属性和原型属性
JSJavaScript对象与原型

如何区分属性是对象自身属性还是来自原型链?用到哪些 API?

判断属性是对象自身还是来自原型,关键在于查找范围:hasOwnProperty 只看自有属性,in 沿原型链检查,Object.hasOwn 是现代替代方案。

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

可见范围不同

  1. 只看自身hasOwnProperty 仅从对象自身键表中查找
  2. 沿链查找in 会往上找原型,直到 Object.prototype
  3. 静态方法Object.hasOwn 不用依赖目标原型,行为稳定

如果对象来自 Object.create(null) 或覆写了 hasOwnProperty,应改用 Object.hasOwn。

核心回答

先记住这个答案

用 in 会触发原型链查找,因此 'toString' in {} 是 true,而 hasOwnProperty 只检查对象自己的属性,不受原型影响。判断自有属性用 Object.hasOwn,判断属性是否可读用 in。当遍历 for...in 时,结合 Object.hasOwn 跳过继承属性,比直接比较更稳妥。

  • in 能看到原型上的属性,hasOwn 只看自身
  • Object.hasOwn 可避开覆写和空原型问题
  • for...in 遍历时用 Object.hasOwn 过滤继承项

查找路径:先看自身,再向上走原型

当用 obj.prop 读取属性时,引擎先查询对象自身的属性表,找不到就沿着内部 [[Prototype]] 指针跳到原型对象,如此反复直到 null。in 运算符完整复刻这条路线:它会依次检查当前对象和每一层原型,只要名称出现过就返回 true。而 hasOwnProperty 本质上调用的是对象内部对自有属性的检查,只访问第一层,不会进一步向上。这就是为什么 {} 上明显看到 toString,但 hasOwnProperty('toString') 返回 false。

原型链可能不止一层,例如 var a = {m:1}, b = Object.create(a);,b 没有 m 属性,但 b.m 可以读到。用 b.hasOwnProperty('m') 会返回 false,因为 m 不在 b 上;用 'm' in b 会得到 true,因为 m 在中间原型 a 上。检测时必须想清楚后续逻辑需要的是“能读”还是“自己拥有”。

另外,Object.prototype.hasOwnProperty 本身也是继承来的方法,若对象原型链被破坏,直接调用可能失败,所以现代静态方法更推荐:Object.hasOwn(obj, key)。

in 与 hasOwn 的不同结果JavaScript
const proto = { inherited: 1 };
const obj = Object.create(proto);
obj.own = 2;

console.log('in inherited:', 'inherited' in obj);
console.log('in own:', 'own' in obj);
console.log('hasOwn inherited:', obj.hasOwnProperty('inherited'));
console.log('Object.hasOwn own:', Object.hasOwn(obj, 'own'));
console.log('Object.hasOwn inherited:', Object.hasOwn(obj, 'inherited'));
查看输出与解释
in inherited: true
in own: true
hasOwn inherited: false
Object.hasOwn own: true
Object.hasOwn inherited: false

前两行 in 都是 true,自身和原型都能命中;后面四行 hasOwn 与 Object.hasOwn 都只认直接定义在 obj 上的 own。

浅拷贝场景:默认配置从原型链迁移

假设你用 Object.create(defaults) 建立实例,defaults 是原型,实例只覆盖部分字段。现在要把实例转成普通对象并传给第三方 JSON 库,若继续用 for...in 会把原型上的默认值也复制出来,产生多余字段且可能覆盖实际配置。一个可行做法是改用 Object.keys(instance),它只返回自身可枚举属性,直接得到用户真正配置的键,例如覆盖了 retry,原型上的 log 就被排除。

如果还要保留自身不可枚举的内部标记,Object.keys 会漏掉,但通常这不是业务想要导出的部分。若确要包含不可枚举,则要用 Object.getOwnPropertyNames,它不会自动过滤可枚举标志。实际选 API 的先后取决于要复制的是值还是全部描述符:普通场景用 Object.keys 最简单,既不需要 hasOwnProperty 也不需要 in,语义最容易维护。

失效条件:空原型与覆写的 hasOwnProperty

Object.create(null) 创建的对象没有任何原型方法,直接调用 obj.hasOwnProperty('x') 会抛出 TypeError,因为根本不存在这个方法。对于这种哈希映射,in 依然可以工作,但无法判断自有键;真正需要自有判断时必须使用 Object.hasOwn,因为它是静态函数,不依赖目标对象的原型链。这也是 Object.hasOwn 被引入的主要原因之一。

另一个失效点是某段代码在 Object.prototype 或中间原型上重写了 hasOwnProperty。比如把 hasOwnProperty 改成永远返回 false,调用 obj.hasOwnProperty('x') 会被欺骗。如果环境不支持 Object.hasOwn,安全写法是借用纯净的原方法:Object.prototype.hasOwnProperty.call(obj, 'x')。这一步要求小心传参,不能直接写成 obj.hasOwnProperty.call(obj, 'x'),因为原始引用可能也被污染。

回答前,多想一步

容易答错的地方

把 in 当作自有判断
“用 if ('foo' in obj) 就能判断是否有自己属性”是错的。in 查找整个原型链,对 {} 测 'toString' 返回 true,但 toString 并非自有属性。检测自有属性需要 Object.hasOwn 或借用 Object.prototype.hasOwnProperty.call。
hasOwnProperty 一定安全
原生 hasOwnProperty 会被对象覆写,也可能因创建时未继承 Object.prototype 而缺失。把它当成万能方法会踩坑。更可靠的是 Object.hasOwn,若必须兼容旧环境,应写 Object.prototype.hasOwnProperty.call(obj, key) 并接受 call 中的 this 指向。
试着用自己的话回答

面试官还会怎么问?

`Object.keys` 和 `hasOwnProperty` 的返回范围有什么差别?

Object.keys 返回自身可枚举字符串键组成的数组;hasOwnProperty 返回单个属性是否存在的布尔值,且不关心 enumerable。若属性不可枚举,Object.keys 不列出,但 hasOwnProperty 仍返回 true。

要判断属性来自原型链的哪一层,怎么办?

从当前对象开始,逐层调用 Object.getOwnPropertyNames(obj) 检查键,再用 Object.getPrototypeOf(obj) 向上推进。hasOwn 只告诉是否存在,不能指出层级,该场景需要遍历原型链。

当属性值为 `undefined` 时,`in` 和 `hasOwnProperty` 是否都返回 `true`?

只要属性名存在,两者都返回 true,因为它们判断的是“拥有该名称”,而不是判断值是否非空。若想区分“值为 undefined”和“无此名称”,可以用 Object.keys 或 Reflect.ownKeys 查看键列表。

从一道题,走向一组知识

把知识连起来

对象与原型

enumerable 如何影响 for...in 和 Object.keys?

同属「对象与原型」专题,接着看 enumerable 与属性遍历 在具体场景中的处理方式。

对象与原型

在原型链上查找属性时,JavaScript 的解析顺序是怎样的?

同属「对象与原型」专题,接着看 JavaScript 原型链属性查找顺序 在具体场景中的处理方式。

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

参考资料

  • Object.hasOwn()

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

本题目录
  1. 先记住这个答案
  2. 查找路径:先看自身,再向上走原型
  3. 浅拷贝场景:默认配置从原型链迁移
  4. 失效条件:空原型与覆写的 hasOwnProperty
  5. 容易答错的地方
  6. 面试官还会怎么问
  7. 把知识连起来
读懂,再试着讲出来

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

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