news 2026/4/18 16:55:12

js遍历数组和对象的常用方法有哪些?

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
js遍历数组和对象的常用方法有哪些?

精通 JS 遍历:数组与对象的高效遍历方法论(2026 版)

遍历是 JavaScript 数据处理的基石,从前端 DOM 渲染到后端数据聚合,几乎所有业务场景都离不开数组和对象的遍历操作。但新手常陷入 “方法用错、性能低效、边界踩坑” 的困境 —— 比如用for...in遍历数组、用forEach强行终止循环、忽略reduce初始值导致异常。本文将从场景适配性能优化避坑指南三个维度,系统拆解数组与对象的遍历方法,结合实战案例和最佳实践,帮你实现 “选对方法、写对代码、用对性能” 的目标。

一、数组遍历:按场景选方法,而非 “一招鲜”

数组遍历的核心是 “匹配业务意图”:是单纯遍历?是生成新数组?是筛选数据?还是聚合计算?不同意图对应不同最优方法,以下按 “基础可控型”“函数式迭代型”“特殊场景型” 分类讲解。

1. 基础可控型遍历(性能优先)

这类方法完全掌控遍历过程,支持终止 / 跳过,适合大数据量、需精细控制的场景。

(1)原生 for 循环(性能天花板)

最底层、性能最优的遍历方式,无任何额外开销,适合 10 万级以上大数据量遍历。

javascript

运行

const arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; // 基础版 for (let i = 0; i < arr.length; i++) { // 终止循环:找到第一个大于5的数就停止 if (arr[i] > 5) { console.log("找到目标值:", arr[i]); break; } console.log("当前值:", arr[i]); } // 性能优化版(缓存长度,避免每次读取arr.length) for (let i = 0, len = arr.length; i < len; i++) { // 跳过偶数 if (arr[i] % 2 === 0) continue; console.log("奇数:", arr[i]); } // 反向遍历(适合从后删除元素的场景) for (let i = arr.length - 1; i >= 0; i--) { if (arr[i] < 3) arr.splice(i, 1); // 从后删除避免索引错乱 } console.log(arr); // [3,4,5,6,7,8,9,10]

核心优势

  • 性能第一,无函数调用、迭代器等额外开销;
  • 支持break(终止)、continue(跳过)、反向遍历;
  • 可直接操作索引,适合修改原数组的场景。
(2)for...of 循环(ES6+,简洁可控)

ES6 迭代器语法,兼顾简洁性和可控性,支持遍历所有可迭代对象(数组、Set、Map、字符串等)。

javascript

运行

const arr = [1, 2, 3, 4, 5]; // 基础遍历元素 for (const item of arr) { if (item === 3) break; // 支持终止 console.log(item); // 1,2 } // 同时获取索引和元素(结合entries()) for (const [index, item] of arr.entries()) { console.log(`索引${index}:${item}`); } // 遍历Set(可迭代对象示例) const set = new Set([1, 2, 3]); for (const item of set) { console.log(item); }

核心优势

  • 语法简洁,比原生 for 循环易读;
  • 支持break/continue,弥补 forEach 的缺陷;
  • 适配所有可迭代对象,通用性强。

2. 函数式迭代方法(可读性优先)

ES5+ 新增的数组原型方法,基于函数式编程思想,无需手动控制索引,是日常开发的主流选择。所有方法均不修改原数组,核心差异在于 “返回值” 和 “终止逻辑”。

核心方法对比表(建议收藏)
方法名核心用途返回值终止逻辑典型场景
forEach单纯遍历无(undefined)无法终止(return 仅跳过当前轮次)列表渲染、无返回值的遍历操作
map映射转换新数组(长度与原数组一致)无终止(遍历所有元素)数据格式转换(如接口数据适配)
filter筛选数据新数组(符合条件的元素)无终止(遍历所有元素)条件筛选(如筛选已完成的任务)
some存在性判断布尔值(true/false)返回 true 时立即终止判断是否有符合条件的元素
every全量判断布尔值(true/false)返回 false 时立即终止判断所有元素是否符合规则
find查找元素第一个符合条件的元素 /undefined返回 true 时立即终止查找唯一元素(如根据 ID 找用户)
findIndex查找索引第一个符合条件的索引 /-1返回 true 时立即终止查找元素位置(如定位错误数据)
reduce聚合计算最终聚合值无终止(遍历所有元素)求和、拼接、扁平化数组等
实战示例(带业务场景)

javascript

运行

const users = [ { id: 1, name: "张三", age: 22, status: "active" }, { id: 2, name: "李四", age: 18, status: "inactive" }, { id: 3, name: "王五", age: 25, status: "active" }, ]; // 1. forEach:渲染用户列表(无返回值) users.forEach(user => { console.log(`用户${user.name}:状态${user.status}`); }); // 2. map:转换数据格式(前端适配) const userOptions = users.map(user => ({ label: user.name, value: user.id })); console.log(userOptions); // [{label: '张三', value: 1}, {label: '李四', value: 2}, {label: '王五', value: 3}] // 3. filter:筛选活跃用户 const activeUsers = users.filter(user => user.status === "active"); console.log(activeUsers); // 张三、王五 // 4. some:判断是否有未成年用户 const hasMinor = users.some(user => user.age < 18); console.log(hasMinor); // false(李四18岁,不满足<18) // 5. every:判断所有用户是否成年 const allAdult = users.every(user => user.age >= 18); console.log(allAdult); // true // 6. find:根据ID查找用户 const targetUser = users.find(user => user.id === 2); console.log(targetUser); // 李四 // 7. reduce:计算所有用户年龄总和 const totalAge = users.reduce((sum, user) => sum + user.age, 0); console.log(totalAge); // 22+18+25=65 // 8. reduce进阶:按状态分组 const groupedUsers = users.reduce((obj, user) => { if (!obj[user.status]) obj[user.status] = []; obj[user.status].push(user); return obj; }, {}); console.log(groupedUsers); // {active: [张三, 王五], inactive: [李四]}
避坑要点:
  • ❌ 不要用forEach尝试终止循环(return无效),改用some/everyfor...of
  • reduce必须传初始值(第二个参数),否则空数组会报错,单元素数组直接返回该元素;
  • map不要用于无返回值的遍历(浪费性能),改用forEach
  • some/every是 “短路遍历”,找到结果立即终止,比forEach+ 判断更高效。

3. 特殊场景遍历

(1)for...in(不推荐遍历数组)

for...in设计初衷是遍历对象,遍历数组时会包含原型链属性,且索引为字符串类型:

javascript

运行

Array.prototype.foo = "原型属性"; const arr = [1, 2, 3]; for (const key in arr) { console.log(key); // 0,1,2,foo(包含原型属性) console.log(typeof key); // string(索引是字符串) }

结论:数组遍历绝对不要用for...in

(2)Array.from(遍历类数组 / 可迭代对象)

适合将 DOM 集合、arguments 等类数组对象转为数组并遍历:

javascript

运行

// 遍历DOM节点列表 const lis = document.querySelectorAll("li"); const liTexts = Array.from(lis, li => li.textContent); console.log(liTexts); // 所有li的文本内容 // 遍历字符串(可迭代对象) const str = "hello"; const charArr = Array.from(str, char => char.toUpperCase()); console.log(charArr); // ['H','E','L','L','O']

二、对象遍历:精准获取键值对

对象遍历的核心是 “区分自身属性 / 原型属性”“可枚举 / 不可枚举属性”“普通键 / Symbol 键”,以下按 “常用程度” 排序讲解。

1. 主流方案:Object.entries () + for...of(ES6+)

最推荐的对象遍历方式,无需过滤原型属性,直接获取键值对,语法简洁:

javascript

运行

const user = { name: "张三", age: 22, status: "active" }; // 遍历键值对 for (const [key, value] of Object.entries(user)) { console.log(`${key}: ${value}`); } // 结合解构+forEach Object.entries(user).forEach(([key, value]) => { console.log(`${key}: ${value}`); });

核心优势

  • 仅遍历对象自身可枚举属性,无需hasOwnProperty过滤;
  • 直接获取 [key, value],无需手动obj[key]取值;
  • 语法统一,与数组遍历风格一致。

2. 基础方案:for...in + hasOwnProperty

传统对象遍历方法,需手动过滤原型属性,否则会遍历到原型链上的可枚举属性:

javascript

运行

const user = { name: "张三", age: 22 }; Object.prototype.foo = "原型属性"; // 正确用法:过滤原型属性 for (const key in user) { if (user.hasOwnProperty(key)) { console.log(`${key}: ${user[key]}`); // 仅name、age } }

适用场景:仅兼容 ES5 的老旧项目,新项目优先用Object.entries()

3. 专项方案:按需求获取键 / 值

  • Object.keys(obj):获取自身可枚举键的数组;
  • Object.values(obj):获取自身可枚举值的数组;

javascript

运行

const user = { name: "张三", age: 22 }; // 获取所有键 const keys = Object.keys(user); // ['name', 'age'] // 获取所有值 const values = Object.values(user); // ['张三', 22] // 遍历键 keys.forEach(key => console.log(key)); // 遍历值 values.forEach(value => console.log(value));

4. 特殊场景:遍历不可枚举 / Symbol 属性

业务中极少用到,但面试常考,需掌握Object.getOwnPropertyNames()Object.getOwnPropertySymbols()

javascript

运行

// 定义不可枚举属性和Symbol键 const symKey = Symbol("id"); const obj = { name: "张三" }; // 定义不可枚举属性 Object.defineProperty(obj, "id", { value: 1001, enumerable: false // 不可枚举 }); // 定义Symbol键 obj[symKey] = "symbol-value"; // 1. 获取所有自身属性(含不可枚举,不含Symbol) const allKeys = Object.getOwnPropertyNames(obj); console.log(allKeys); // ['name', 'id'] // 2. 获取所有Symbol键 const symKeys = Object.getOwnPropertySymbols(obj); console.log(symKeys); // [Symbol(id)] // 3. 遍历所有自身属性(含不可枚举+Symbol) const allProps = [...allKeys, ...symKeys]; allProps.forEach(key => { console.log(`${key}: ${obj[key]}`); });

三、选型决策树(快速选对方法)

数组遍历选型

预览

查看代码

无返回值

新数组(映射)

新数组(筛选)

布尔值(存在性)

单个元素/索引

聚合值(求和/分组)

数组遍历

是否需要终止/跳过?

for循环 / for...of

是否需要返回值?

forEach

map

filter

some/every

find/findIndex

reduce

graph TD A[数组遍历] --> B{是否需要终止/跳过?} B -->|是| C[for循环 / for...of] B -->|否| D{是否需要返回值?} D -->|无返回值| E[forEach] D -->|新数组(映射)| F[map] D -->|新数组(筛选)| G[filter] D -->|布尔值(存在性)| H[some/every] D -->|单个元素/索引| I[find/findIndex] D -->|聚合值(求和/分组)| J[reduce]

无返回值

新数组(映射)

新数组(筛选)

布尔值(存在性)

单个元素/索引

聚合值(求和/分组)

数组遍历

是否需要终止/跳过?

for循环 / for...of

是否需要返回值?

forEach

map

filter

some/every

find/findIndex

reduce

豆包

你的 AI 助手,助力每日工作学习

对象遍历选型

预览

查看代码

生成失败,请重试

graph TD A[对象遍历] --> B{是否需要键值对?} B -->|是| C[Object.entries() + for...of] B -->|否| D{仅需键?} D -->|是| E[Object.keys()] D -->|否| F[Object.values()] A --> G{是否需遍历不可枚举/Symbol?} G -->|是| H[Object.getOwnPropertyNames() + Object.getOwnPropertySymbols()] G -->|否| I[主流方案]

生成失败,请重试

豆包

你的 AI 助手,助力每日工作学习

四、性能与最佳实践

1. 性能对比(10 万条数据测试)

方法执行时间(ms)适用场景
for 循环~5大数据量、需极致性能
for...of~8中等数据量、需简洁可控
forEach~10小数据量、无终止需求
map/filter~12小数据量、需返回新数组
for...in(数组)~50绝对避免

2. 最佳实践

  • ✅ 业务代码优先保证可读性,大数据量(10 万 +)再优化性能;
  • ✅ 数组遍历优先用map/filter/some/every/reduce(语义化),而非 forEach + 手动逻辑;
  • ✅ 对象遍历优先用Object.entries(),替代for...in
  • ✅ 避免在遍历中修改原数组(如 splice/push),易导致索引错乱;
  • ✅ 遍历嵌套数据时,优先扁平化(如flatMap)后再遍历,减少嵌套层级。

总结

  1. 数组遍历的核心是 “匹配业务意图”:需终止用for/for...of,需映射用map,需筛选用filter,需聚合用reduce
  2. 对象遍历优先选择Object.entries() + for...of,无需手动过滤原型属性,语法简洁;
  3. 选择遍历方法的核心原则:语义化 > 简洁性 > 性能,仅在大数据量场景下优先考虑性能。

掌握这些遍历方法,不仅能写出更优雅的代码,更能避免常见的边界错误。记住:没有 “最好” 的方法,只有 “最适合” 当前场景的方法。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/17 23:36:52

MySQL事件功能简介

MySQL 的事件调度器&#xff08;Event Scheduler&#xff09;提供了一种便捷的方法来定时执行 SQL 语句&#xff0c;从而实现数据维护、报告生成等自动化操作。本文将详细介绍 MySQL 的事件功能&#xff0c;并说明如何使用 Navicat 管理这些事件。 1. 什么是 MySQL 事件调度器&…

作者头像 李华
网站建设 2026/4/17 8:27:47

mysql之逻辑函数

MySQL 中的逻辑函数允许你根据条件对数据进行判断和选择。以下是一些常用逻辑函数的详细介绍和示例&#xff1a; IF(expr1, expr2, expr3) 如果 expr1 是真&#xff08;非零和非 NULL&#xff09;&#xff0c;IF() 函数返回 expr2&#xff0c;否则返回 expr3。 SELECT IF(1 0, …

作者头像 李华
网站建设 2026/4/17 17:08:37

光特通信40G光模块:适配各种需求的高速传输方案

在数据中心密集连接、企业园区网络升级、工业极端环境部署这些场景里&#xff0c;40G光模块是保证数据高速传输的核心部件。光特通信作为全球光通信解决方案服务商&#xff0c;有20年的技术积累&#xff0c;打造了全系列40G光模块产品&#xff0c;涵盖普通环境、长距离、工业恶…

作者头像 李华
网站建设 2026/4/16 23:50:05

都说网络安全前景好,到底好在哪?3 个数据给你答案

都说网络安全前景好&#xff0c;到底好在哪&#xff1f;3 个数据给你答案 数字化时代里&#xff0c;网络安全早已不是“可选项”而是“必选项”。从政府机关到互联网公司&#xff0c;从金融能源到日常消费&#xff0c;各行各业的安全防护需求持续爆发&#xff0c;让这个行业成…

作者头像 李华
网站建设 2026/4/17 21:31:41

MySQL中存储过程(详解,一篇就够了!!!)

一、MySQL中什么事存储过程&#xff1f; 存储过程是事先经过编译并存储在数据库中的一段SOL语句的集合&#xff0c;调用存储过程可以简化应用开发人员的很多工作&#xff0c;减少数据在数据库和应用服务器之间的传输&#xff0c;对于提高数据处理的效率是有好处的。存储过程思…

作者头像 李华