JS 对象遍历的几种实现方法

 更新时间:2026年02月18日 09:34:12   作者:不想秃头的程序员  
JavaScript 开发中,对象是最常用的数据结构之一,几乎所有业务场景都会涉及到对象的遍历,比如获取对象的所有属性、筛选,下面就来介绍一下几种对象遍历的方法,需要的朋友可以参考下

在 JavaScript 开发中,对象(Object)是最常用的数据结构之一,几乎所有业务场景都会涉及到对象的遍历——比如获取对象的所有属性、筛选符合条件的键值对、批量处理对象数据等。

但很多新手在面对对象遍历时,总会困惑:for...inObject.keys() 有什么区别?什么时候用 Object.values()?如何遍历对象的原型链属性?

今天这篇文章,就带你彻底吃透 JS 对象遍历的所有常用方法,从基础用法到进阶技巧,再到实战场景对比,帮你避开坑点、灵活运用。

一、先明确:什么是 JS 对象?

在开始遍历之前,我们先简单回顾下 JS 对象的基础——对象是由 键(key)值(value) 组成的无序集合,键通常是字符串(ES6 后支持 Symbol),值可以是任意数据类型(字符串、数字、函数、对象等)。

示例对象(后文所有方法均基于此对象演示):

// 基础对象
const user = {
  name: "掘金小册",
  age: 3,
  gender: "male",
  isVip: true,
  hobbies: ["coding", "writing"],
  // 方法
  sayHello: function() {
    console.log("Hello, Juejin!");
  }
};

// 原型链上的属性(用于后续演示区别)
Object.prototype.protoProp = "我是原型链上的属性";

二、常用对象遍历方法(按使用频率排序)

以下方法是开发中最常用的,重点掌握前 4 种,基本能覆盖 90%+ 的业务场景。

1. for...in 循环(最基础,遍历可枚举属性)

for...in 是最早的对象遍历方法,也是最基础的方式,它会遍历对象自身的可枚举属性原型链上的可枚举属性(这是它的坑点,也是重点注意事项)。

基础用法

// for...in 遍历对象
for (let key in user) {
  console.log("键:", key); // 输出对象的键
  console.log("值:", user[key]); // 输出对应的值
}

输出结果(重点看最后一行)

键: name,值: 掘金小册
键: age,值: 3
键: gender,值: male
键: isVip,值: true
键: hobbies,值: [ 'coding', 'writing' ]
键: sayHello,值: [Function: sayHello]
键: protoProp,值: 我是原型链上的属性

核心注意事项(避坑关键)

  • 会遍历原型链上的可枚举属性(如上面的 protoProp),这通常不是我们想要的,所以一定要搭配 hasOwnProperty() 使用。
  • 不能遍历 Symbol 类型的键(后文会讲专门遍历 Symbol 的方法)。

正确用法(搭配 hasOwnProperty)

for (let key in user) {
  // 只遍历对象自身的属性,过滤原型链属性
  if (user.hasOwnProperty(key)) {
    console.log("键:", key, "值:", user[key]);
  }
}

这样就不会输出原型链上的 protoProp 了,这是 for...in 的标准用法。

2. Object.keys() + forEach(最常用,遍历自身可枚举键)

ES5 新增的 Object.keys() 方法,会返回一个包含对象自身可枚举属性键的数组(不包含原型链属性,也不包含 Symbol 键),再搭配 forEach 循环,是目前开发中最常用的遍历方式。

基础用法

// 1. 获取对象自身的所有可枚举键,返回数组
const keys = Object.keys(user);
console.log(keys); // 输出:['name', 'age', 'gender', 'isVip', 'hobbies', 'sayHello']

// 2. 搭配 forEach 遍历
Object.keys(user).forEach(key => {
  console.log("键:", key);
  console.log("值:", user[key]);
});

核心优势

  • 自动过滤原型链属性,无需手动写 hasOwnProperty(),更简洁、更安全。
  • 返回的是数组,可直接使用数组的方法(如 forEachmapfilter 等),灵活度更高。

实战场景

筛选对象中值为布尔类型的键值对:

const boolProps = {};
Object.keys(user).forEach(key => {
  if (typeof user[key] === "boolean") {
    boolProps[key] = user[key];
  }
});
console.log(boolProps); // 输出:{ isVip: true }

3. Object.values() + forEach(遍历自身可枚举值)

ES2017(ES8)新增的 Object.values() 方法,和 Object.keys() 对应,它会返回一个包含对象自身可枚举属性值的数组(不包含原型链属性、Symbol 键对应的值)。

基础用法

// 获取对象自身的所有可枚举值,返回数组
const values = Object.values(user);
console.log(values); 
// 输出:['掘金小册', 3, 'male', true, ['coding', 'writing'], [Function: sayHello]]

// 搭配 forEach 遍历值
Object.values(user).forEach(value => {
  console.log("值:", value);
});

实战场景

统计对象中所有数值类型的值的总和:

const sum = Object.values(user).reduce((total, value) => {
  // 只累加数值类型的值
  return typeof value === "number" ? total + value : total;
}, 0);
console.log(sum); // 输出:3

4. Object.entries() + forEach(遍历自身可枚举键值对)

同样是 ES2017 新增的方法,Object.entries() 是最灵活的遍历方法,它会返回一个包含对象自身可枚举键值对的二维数组(每个子数组是 [key, value]),完美兼顾键和值的获取。

基础用法

// 获取对象自身的所有可枚举键值对,返回二维数组
const entries = Object.entries(user);
console.log(entries);
// 输出:[
//   ['name', '掘金小册'],
//   ['age', 3],
//   ...
// ]

// 搭配 forEach 遍历键值对
Object.entries(user).forEach(([key, value]) => {
  // 解构赋值,直接获取 key 和 value,更简洁
  console.log(`键:${key},值:${value}`);
});

实战场景

将对象转换为 Map(Map 支持更多灵活操作):

// Object.entries() 可直接作为 Map 的构造参数
const userMap = new Map(Object.entries(user));
console.log(userMap.get("name")); // 输出:掘金小册

// 遍历 Map(补充)
userMap.forEach((value, key) => {
  console.log("键:", key, "值:", value);
});

5. 进阶:遍历 Symbol 类型的键

如果对象的键是 Symbol 类型(ES6 新增,用于表示唯一键),上面的 4 种方法都无法遍历到,此时需要使用 Object.getOwnPropertySymbols() 方法。

示例用法

// 定义一个包含 Symbol 键的对象
const obj = {
  [Symbol("id")]: 123,
  name: "测试"
};

// 遍历 Symbol 类型的键
Object.getOwnPropertySymbols(obj).forEach(symbolKey => {
  console.log("Symbol 键:", symbolKey);
  console.log("对应值:", obj[symbolKey]); // 输出:123
});

6. 高阶:遍历所有属性(自身+原型链,可枚举+不可枚举)

开发中很少用到,但面试可能会问——如果需要遍历对象自身的所有属性(包括不可枚举),或者原型链上的所有属性,可以使用以下方法:

  • Object.getOwnPropertyNames(obj):返回对象自身的所有属性键(包括不可枚举,不包括 Symbol)。
  • Reflect.ownKeys(obj):返回对象自身的所有属性键(包括不可枚举、Symbol 键),相当于 Object.keys(obj) + Object.getOwnPropertySymbols(obj) + 不可枚举键

示例

// 遍历自身所有属性(包括不可枚举)
const allOwnKeys = Object.getOwnPropertyNames(user);
console.log(allOwnKeys); // 包含 sayHello(函数也是属性)

// 遍历自身所有属性(包括不可枚举、Symbol)
const allKeys = Reflect.ownKeys(user);
console.log(allKeys);

三、常用方法对比表(一目了然)

方法遍历范围是否包含原型链是否包含 Symbol 键是否包含不可枚举适用场景
for...in自身可枚举 + 原型链可枚举是(需手动过滤)兼容旧环境,需过滤原型链
Object.keys()自身可枚举键仅需获取键,搭配数组方法
Object.values()自身可枚举值仅需获取值,如统计、筛选
Object.entries()自身可枚举键值对需同时操作键和值(最常用)
Object.getOwnPropertySymbols()自身 Symbol 键遍历 Symbol 类型的键
Reflect.ownKeys()自身所有键(可枚举+不可枚举+Symbol)高阶场景,需获取所有自身属性

四、避坑指南(新手必看)

  1. 永远不要用 for...in 遍历数组!虽然数组也是对象,但 for...in 会遍历数组的原型链属性,还会按照“字符串索引”排序,导致遍历顺序错乱。
  2. 使用 for...in 必须搭配 hasOwnProperty(),否则会遍历到原型链上的无关属性,导致业务逻辑出错。
  3. Symbol 类型的键无法被 Object.keys()Object.values()for...in 遍历,需用专门的 Object.getOwnPropertySymbols()
  4. 对象是无序的!虽然 ES6 后对象的键会按照“数字优先、插入顺序”排列,但不要依赖对象的遍历顺序来实现业务逻辑(如需有序,建议用 Map)。

五、实战案例(综合运用)

需求:遍历一个用户对象,筛选出所有非函数类型的属性,将其转换为查询字符串(如:name=掘金小册&age=3)。

const user = {
  name: "掘金小册",
  age: 3,
  gender: "male",
  isVip: true,
  sayHello: function() {
    console.log("Hello");
  }
};

// 1. 遍历对象,筛选非函数属性
const queryArr = Object.entries(user).filter(([key, value]) => {
  // 排除函数类型的属性
  return typeof value !== "function";
}).map(([key, value]) => {
  // 将键值对转换为 "key=value" 格式
  return `${key}=${encodeURIComponent(value)}`;
});

// 2. 拼接为查询字符串
const queryStr = queryArr.join("&");
console.log(queryStr);
// 输出:name=掘金小册&age=3&gender=male&isVip=true

解析:这里结合了 Object.entries()filter()map() 方法,既遍历了键值对,又完成了筛选和格式转换,是开发中非常典型的场景。

六、总结

JS 对象遍历的核心是“明确遍历范围”——你是要遍历自身属性,还是原型链属性?是要键、值,还是键值对?是包含 Symbol 或不可枚举属性?

对于绝大多数开发场景:

  • 仅需键 → 用 Object.keys()
  • 仅需值 → 用 Object.values()
  • 需键值对 → 用 Object.entries()(最常用)
  • 兼容旧环境 → 用 for...in + hasOwnProperty()

到此这篇关于JS 对象遍历的几种实现方法的文章就介绍到这了,更多相关JS 对象遍历内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • JavaScript寄生组合式继承原理与用法分析

    JavaScript寄生组合式继承原理与用法分析

    这篇文章主要介绍了JavaScript寄生组合式继承,结合实例形式分析了javascript寄生组合式继承的原理、定义与简单使用方法,需要的朋友可以参考下
    2019-01-01
  • 一文解析JavaScript模块构建的三种方式

    一文解析JavaScript模块构建的三种方式

    在现代Web开发中,JavaScript库的构建和打包是一个至关重要的环节,不同的构建方式可以影响到库的性能、可维护性和适用性,本文将深入剖析三种主要的JavaScript模块构建方式:CommonJS、ES模块和AMD,我们将深入探讨它们的工作原理、适用场景以及示例代码
    2023-08-08
  • Typescript 中的 interface 和 type 到底有什么区别详解

    Typescript 中的 interface 和 type 到底有什么区别详解

    这篇文章主要介绍了Typescript 中的 interface 和 type 到底有什么区别详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2019-06-06
  • JS数组中sort的用法(避坑版)

    JS数组中sort的用法(避坑版)

    本文主要介绍了JS数组中sort的用法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2025-06-06
  • js实现购物网站商品放大镜效果

    js实现购物网站商品放大镜效果

    这篇文章主要为大家详细介绍了js实现购物网站商品放大镜效果,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2021-10-10
  • JS实现图片居中悬浮效果

    JS实现图片居中悬浮效果

    这篇文章给大家分享的是通过JS实现图片垂直居中悬浮,不跟随滚动条飘动的效果,有兴趣的朋友跟着学习下吧。
    2017-12-12
  • webstorm中配置Eslint的两种方式及差异比较详解

    webstorm中配置Eslint的两种方式及差异比较详解

    这篇文章主要介绍了webstorm中配置Eslint的两种方式及差异比较详解,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2018-10-10
  • javascript中关于执行环境的杂谈

    javascript中关于执行环境的杂谈

    如你所知,javascript里执行环境是作为一个最核心的概念存在的。相信广大FE筒子们对于这个概念不会陌生,它定义了变量或函数有权访问其他数据范围以及其行为。
    2011-08-08
  • 如何写出优雅的JS 代码

    如何写出优雅的JS 代码

    在开发中,变量名,函数名一般要做到清晰明了,尽量做到看名字就能让人知道你的意图,所以变量和函数命名是挺重要,今天来看看如果较优雅的方式给变量和函数命名。
    2021-05-05
  • javascript onkeydown,onkeyup,onkeypress,onclick,ondblclick

    javascript onkeydown,onkeyup,onkeypress,onclick,ondblclick

    昨天群里面的朋友问了个比较有意思的问题,keydown,keyup,keypress事件的先后顺序。
    2009-02-02

最新评论