30 seconds of code:JavaScript 中 for...in、for...of 与 forEach() 三种迭代方式的完整对比
教程文档【免费下载链接】30-seconds-of-codeCoding articles to level up your development skills项目地址https://gitcode.com/gh_mirrors/30/30-seconds-of-code点击查看免费下载遍历数组、对象、字符串乃至Map、Set是 JavaScript 开发中最高频的操作之一但for...in、for...of与Array.prototype.forEach()三者到底有何区别却常常让初学者甚至资深开发者混淆。本篇基于 30 seconds of code 仓库中的核心文档 for-in-for-of-foreach系统梳理三种迭代方式的适用对象、取值语义、边界陷阱并结合作者仓库内 array-map-vs-foreach、for-each-right、for-loop-early-break、async-array-loops 等关联片段给出每个场景下最正确的选型结论。读完本文你将能一眼判断任意数据结构该用哪种迭代方式并避开原型链污染、TypeError: not iterable、回调无法提前退出等常见坑。for...in遍历可枚举属性含继承属性for...in用于遍历一个对象的所有可枚举属性包括继承自原型链的可枚举属性。它适用于数组、字符串和普通对象但不能用于Map或Set。看文档中的四个例子for (let prop in [a, b, c]) console.log(prop); // 0, 1, 2 (数组索引) for (let prop in str) console.log(prop); // 0, 1, 2 (字符串索引) for (let prop in {a: 1, b: 2, c: 3}) console.log(prop); // a, b, c (对象属性名) for (let prop in new Set([a, b, a, d])) console.log(prop); // undefined (没有可枚举属性)关键点在于for...in取出的是键key而不是值数组上取出的是索引下标字符串上取出的是字符下标普通对象上取出的是属性名。而对Set来说它内部并没有暴露可枚举属性因此循环体内什么都拿不到。警惕原型链上的可枚举属性for...in会沿原型链向上遍历所有可枚举属性这通常是我们并不想要的行为。仓库中的另一篇文章 eslint-refactor-for-in 开篇就引出了 ESLint 对它的经典警告for..in loops iterate over the entire prototype chain, which is virtually never what you want. Use Object.{keys,values,entries}, and iterate over the resulting array.eslint(no-restricted-syntax)如果你确实想只遍历对象自身的键需要配合Object.prototype.hasOwnProperty()做过滤而更推荐的做法是直接用Object.keys()、Object.values()、Object.entries()把键/值/键值对先取成数组再交给数组方法处理。该文给出的三个替代方案如下const data [3, 4]; // 与 for (let k in data) console.log(k) 行为完全一致 Object.keys(data).forEach(k console.log(k)); // 0 1 // 只想拿值时用 Object.values() Object.values(data).forEach(v console.log(v)); // 3 4 // 键和值都要时用 Object.entries() Object.entries(data).forEach(e console.log(e[0], e[1])); // 0 3, 1 4这三个静态方法都只返回对象自身的键/值/键值对天然绕开了原型链问题是重构for...in最稳妥的手段。for...of遍历可迭代对象的值for...of用于遍历可迭代iterable对象取出的是元素的值而不是属性。它适用于数组、字符串、Map、Set但不能用于普通对象——因为普通对象默认没有实现迭代器协议。for (let val of [a, b, c]) console.log(val); // a, b, c (数组元素值) for (let val of str) console.log(val); // s, t, r (字符串字符) for (let val of {a: 1, b: 2, c: 3}) console.log(val); // TypeError: obj is not iterable for (let val of new Set([a, b, a, d])) console.log(val); // a, b, d (Set 去重后的值)注意上面普通对象的例子会直接抛出TypeError: not iterable因为for...of依赖目标对象的Symbol.iterator方法而普通对象并没有实现它。同时这个例子也顺带展示了Set的一个特性元素自动去重[a, b, a, d]迭代出来只有a, b, d。想要索引用Array.prototype.entries()for...of默认只能拿到值这常被拿来与forEach()的「值 索引」能力做对比。但仓库中的 index-for-of-loop 指出这其实不是限制——结合Array.prototype.entries()即可同时拿到索引和值const items [a, b, c]; for (let [index, item] of items.entries()) { console.log(${index}: ${item}); } // LOGS: 0: a, 1: b, 2: c字符串可以先用展开运算符...转成数组再如法炮制Map.prototype.entries()和Set.prototype.entries()也提供了完全相同的用法。与 async/await 的天然亲和力for...of与for循环在异步场景下还有一个显著优势循环体内可以使用await且所有 Promise 会按顺序依次执行。仓库中的 async-array-loops 给出了对照const asyncUppercase item new Promise(resolve setTimeout(() resolve(item.toUpperCase()), Math.floor(Math.random() * 1000)) ); const uppercaseItems async () { const items [a, b, c]; for (item of items) { const uppercaseItem await asyncUppercase(item); console.log(uppercaseItem); } console.log(Items processed); }; // Logs: A, B, C, Items processed (严格按顺序)如果你需要并行执行则改用Promise.all()Array.prototype.map()但千万不要把async回调直接传给forEach()因为它不会等待 Promise 完成代码会继续往下跑导致「Items processed」先于异步结果输出。Array.prototype.forEach()数组元素的专用方法forEach()是Array原型上的方法只能作用于数组以及类数组对象但它在遍历时可以同时访问元素的值和索引[a, b, c].forEach( val console.log(val) // a, b, c (数组元素值) ); [a, b, c].forEach( (val, i) console.log(i) // 0, 1, 2 (数组索引) );回调函数还接收可选的第三个参数——数组本身这在需要内部引用原数组如合并相邻元素时很有用。返回 undefined与 map() 的本质区别forEach()的返回值恒为undefined它只负责「对每个元素执行副作用」不产生新数组。这与Array.prototype.map()形成鲜明对照——map()返回一个由回调结果构成的新数组代表「转换」。仓库中的 array-map-vs-foreach 用一个例子把二者区分得清清楚楚const numbers [1, 2, 3, 4, 5]; numbers.forEach(num console.log(num * 2)); // 无返回值仅输出: 2, 4, 6, 8, 10 const doubledNumbers numbers.map(num num * 2); // 返回新数组: [2, 4, 6, 8, 10]一句话记忆法map()是转换transformationforEach()是遍历iteration。当你只是想对每个元素执行副作用打印、写入、发请求时用forEach()当你想基于原数组生成一个新数组时务必用map()。两个不能忽略的短板不能 break、不能 awaitforEach()的第一个短板是无法提前跳出循环——break、continue、return都无法终止它。仓库中的 for-loop-early-break 展示了一个典型场景判断两个数组是否相等用forEach()即使已经发现不相等也会把largeArray全部遍历完const smallArray [0, 2]; const largeArray Array.from({ length: 1000 }, (_, i) i); const areEqual (a, b) { let result true; a.forEach((x, i) { if (!result) return; if (b[i] undefined || x ! b[i]) result false; }); return result; }; areEqual(largeArray, smallArray); // false // 但会白白遍历 largeArray 的全部 1000 项而换成传统for循环加提前return一遇到第一个不匹配项就立刻退出const areEqual (a, b) { for (let i in a) { if (b[i] undefined || a[i] ! b[i]) return false; } return true; }; areEqual(largeArray, smallArray); // false // 只会遍历到第一个不匹配的位置就返回第二个短板在前文已提async回调传入forEach()后外层await并不会等待所有异步操作完成输出顺序与预期完全不可控见 async-array-loops 中的第三种写法。反向遍历slice reverse forEachforEach()默认从左到右遍历。若想从右向左仓库中的 for-each-right 给出了一个优雅且不污染原数组的组合拳——先slice()浅拷贝再reverse()最后forEach()const forEachRight (arr, callback) arr.slice().reverse().forEach(callback); forEachRight([1, 2, 3, 4], val console.log(val)); // 4, 3, 2, 1三分钟选型速查表迭代方式取出的是什么适用对象不适用对象能否提前退出是否支持 await 顺序执行for...in键含继承的可枚举属性数组、字符串、普通对象Map、Set可以break/return可以for...of值数组、字符串、Map、Set普通对象非 iterable可以break/return可以Array.prototype.forEach()值 索引 数组本身数组普通对象、Map、Set不可以不可以异步会乱序/不等补充两条实战经验遍历普通对象的键/值优先Object.keys()/Object.values()/Object.entries() 数组方法彻底避开for...in的原型链遍历问题参考 eslint-refactor-for-in需要索引的for...of用items.entries()解构[index, item]兼顾可读性与break能力参考 index-for-of-loop需要提前退出或按序 await 的场景直接用for/for...of这是数组方法给不了的能力参考 for-loop-early-break 与 async-array-loops。相关阅读Array.prototype.map() 与 Array.prototype.forEach() 的区别返回值决定两者不可互换在 for...of 循环中获取数组索引entries()的妙用从右向左遍历数组slice().reverse().forEach()组合需要提前退出时使用 for 循环forEach()无法 break 的解决方案JavaScript 异步数组循环for...of顺序执行 vsPromise.all()并行执行重构 for...in 以规避 ESLint 警告Object.keys/values/entries替代方案上述片段统一收录于 JavaScript Array Methods 与 JavaScript Interview Questions 两个集合中前者汇总了数组遍历与变换的常用技巧后者则把forEach与map的对比列为高频面试题之一赞分享教程文档【免费下载链接】30-seconds-of-codeCoding articles to level up your development skills项目地址https://gitcode.com/gh_mirrors/30/30-seconds-of-code点击查看免费下载相关推荐30 seconds of codeJavaScript 数组比较的完整实战指南30 seconds of codeJavaScript 数组比较的完整实战指南 导读 在 JavaScript 中比较两个数组是否相等是开发中最高频也教程文档30-seconds-of-code重构 for...in 循环以消除 ESLint 警告的三种方案30 seconds of code重构 for...in 循环以消除 ESLint 警告的三种方案 ESLint 是 JavaScript 开发中最常用的静教程文档30 seconds of codeJavaScript 异步数组循环的三种方案与避坑指南30 seconds of codeJavaScript 异步数组循环的三种方案与避坑指南 异步操作与数组循环的组合是 JavaScript 开发中最容易踩坑教程文档创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

相关新闻

VS Code 新能力:AI 智能体通过 AHP 协议操作 Dev Container

VS Code 新能力:AI 智能体通过 AHP 协议操作 Dev Container

1. 这次更新到底改了什么:从"人操作容器"到"智能体操作容器"VS Code 每次版本更新都会塞进一堆东西,但这次有一个变化值得单独拎出来说:AI 智能体可以通过 AHP 协议去操作 Dev Container 了。这句话拆开看,信…

2026/10/4 9:49:38 阅读更多 →
VoiceStudio:面向语音开发者的本地化全栈工作台

VoiceStudio:面向语音开发者的本地化全栈工作台

1. VoiceStudio 是什么:一个面向语音开发者的全栈式本地化工作台VoiceStudio 这个名字乍一听像某个商业 SaaS 服务,但结合 Electron、k2-fsa、OmniVoice、Docker 这些关键词,它实际是一个基于桌面端构建、深度集成语音处理工具链的开源开发工…

2026/10/4 9:49:38 阅读更多 →
什么是MCP|工作原理是什么|怎么使用MCP|图解MCP:从JSON-RPC到TaoToken统一Key的实战拆解

什么是MCP|工作原理是什么|怎么使用MCP|图解MCP:从JSON-RPC到TaoToken统一Key的实战拆解

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/4 9:48:37 阅读更多 →

最新新闻

Android MVVM 架构模式实战指南:ViewModel、LiveData 与 StateFlow 在 developer-roadmap 中的系统解读

Android MVVM 架构模式实战指南:ViewModel、LiveData 与 StateFlow 在 developer-roadmap 中的系统解读

文档教程知识库 【免费下载链接】developer-roadmap Interactive roadmaps, guides and other educational content to help developers grow in their careers. 项目地址: https://gitcode.com/GitHub_Trending/de/developer-roadmap 点击查看 免费下载 MVVM&…

2026/10/4 10:23:06 阅读更多 →
OpenShell:把Win10/Win11开始菜单调回经典样式,安装配置与进阶玩法全攻略

OpenShell:把Win10/Win11开始菜单调回经典样式,安装配置与进阶玩法全攻略

如果你是从 Windows 7 一路用过来的老用户,第一次面对 Windows 8/10/11 那个铺满磁贴和推荐应用的新开始菜单时,多半会有一种感觉:微软把我用了几十年的入口换掉了,我却连控制面板都找不着。我第一次升级到 Win10 之后真的纠结了很…

2026/10/4 10:23:06 阅读更多 →
JavaWeb学生信息管理系统大作业:完整源码+建表SQL+课程设计报告,跑通CRUD全流程

JavaWeb学生信息管理系统大作业:完整源码+建表SQL+课程设计报告,跑通CRUD全流程

简介:这是一套面向计算机相关专业学生的 JavaWeb 期末大作业完整项目,以学生信息管理系统为主题,适合正在准备课程设计、期末大作业或需要项目实战练习的学习者参考使用。项目结构完整,包含源代码、数据库建表脚本与配套课程设计报…

2026/10/4 10:23:06 阅读更多 →
主流AI论文工具梯队榜(2026 深度测评)

主流AI论文工具梯队榜(2026 深度测评)

基于功能完整性、学术适配性、用户反馈及操作便捷性,以下是当前主流AI论文写作工具的深度测评榜单,按综合使用价值从高到低进行排序,并附上核心功能亮点与适用人群说明。🏆 第一梯队:全流程学术解决方案(★…

2026/10/4 10:23:06 阅读更多 →
FARO优化器:收益—风险约束下的自适应更新机制与实操调参

FARO优化器:收益—风险约束下的自适应更新机制与实操调参

1. 从梯度下降到决策视角:为什么要把优化器当成投资组合来管做深度学习训练的人都有一个共同的体感:模型能不能收敛、收敛得快不快、最终泛化好不好,很大程度上不取决于网络结构有多花哨,而取决于优化器在参数空间里怎么走。SGD、…

2026/10/4 10:23:06 阅读更多 →
web-video-presentation 章节开发完全指南:从“视频感“设计到代码红线与完工自检

web-video-presentation 章节开发完全指南:从“视频感“设计到代码红线与完工自检

人工智能AI 技能/插件提示工程 【免费下载链接】garden-skills ConardLis open-source Skills collection, featuring web design, knowledge retrieval, image generation, and more. 项目地址: https://gitcode.com/GitHub_Trending/we/garden-skills 点击查看 免…

2026/10/4 10:22:05 阅读更多 →

日新闻

KT148A语音芯片外挂8002D功放的工程实践指南

KT148A语音芯片外挂8002D功放的工程实践指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/4 1:00:58 阅读更多 →
LLC谐振变换器增益公式推导:从FHA等效到完整归一化表达式

LLC谐振变换器增益公式推导:从FHA等效到完整归一化表达式

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/4 1:00:58 阅读更多 →
ARM架构深度解析:从RISC设计理念到交叉编译实战

ARM架构深度解析:从RISC设计理念到交叉编译实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/4 1:00:58 阅读更多 →

周新闻

KT148A语音芯片外挂8002D功放的工程实践指南

KT148A语音芯片外挂8002D功放的工程实践指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/4 1:00:58 阅读更多 →
LLC谐振变换器增益公式推导:从FHA等效到完整归一化表达式

LLC谐振变换器增益公式推导:从FHA等效到完整归一化表达式

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/4 1:00:58 阅读更多 →
ARM架构深度解析:从RISC设计理念到交叉编译实战

ARM架构深度解析:从RISC设计理念到交叉编译实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/4 1:00:58 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/2 10:36:31 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/4 9:43:54 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/3 9:42:36 阅读更多 →