news 2026/10/9 2:09:28

jstips 第 79 號技巧:JavaScript 陣列遍歷方法全解析(while / for / forEach / map / reduce / filter / every / some)

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
jstips 第 79 號技巧:JavaScript 陣列遍歷方法全解析(while / for / forEach / map / reduce / filter / every / some)
  • 教程

【免费下载链接】jstips

This is about useful JS tips!

项目地址:https://gitcode.com/gh_mirrors/js/jstips
点击查看免费下载

這篇文章是 jstips 專案中第 79 號技巧「循環陣列」的完整展開,原始內容收錄於 _posts/zh_TW/javascript/2017-06-15-looping-over-arrays.md(英文原版見 _posts/en/javascript/2017-06-15-looping-over-arrays.md)。文章從最典型的while、for開始,一路延伸到 ES5/ES6 標準加入的forEach、map、reduce、filter、every、some等高階遍歷方法,並結合倉庫內相關技巧(短路遍歷、模數無限迴圈、reduce進階用法)補足原理與實戰細節。讀完後你將能依據「是否需要回傳值」「是否需要中途跳出」「是否需要聚合結果」等需求,在八種寫法中做出正確選擇。

從典型迴圈到標準擴充:一次看懂八種遍歷寫法

JavaScript 對陣列的遍歷有非常豐富的寫法。原文件的組織邏輯是「先看傳統寫法,再看語言標準後續加入的抽象方法」——後者讓我們把「怎麼走訪」與「對每個元素做什麼」分離開來,程式碼更短、意圖更清晰。以下每一種方法都配上可直接執行的範例與輸出說明。

註:繁體中文版原文中的for範例與map範例輸出存在筆誤(index++被誤寫成index, index++、${squares}被誤寫成${array}),本文依英文原版修正後呈現。

while 迴圈

while是條件式迴圈:先判斷條件,條件成立才執行迴圈體,因此迴圈體可能完全不會執行。需要自行維護索引計數器:

let index = 0; const array = [1,2,3,4,5,6]; while (index < array.length) { console.log(array[index]); index++; }

這種寫法的優點是控制力最強——break、continue、return都可用;缺點是索引的遞增必須手動處理,漏寫index++會造成無限迴圈。

典型 for 迴圈

for把「初始化、條件判斷、索引更新」收斂到一行,是傳統寫法中最常用的形式:

const array = [1,2,3,4,5,6]; for (let index = 0; index < array.length; index++) { console.log(array[index]); }

這裡使用let宣告index,讓每次疊代的變數作用域限定在當次迴圈內——這正是 _posts/en/javascript/2016-08-25-keyword-var-vs-let.md 所探討的var與let差異的典型應用場景:若改用var,迴圈結束後index仍會殘留在外層作用域,且閉包捕獲的是同一個變數,容易產生預期之外的結果。

forEach

forEach是 ES5 加入的遍歷方法,回呼函式依序收到三個參數:current_value(目前元素)、index(索引)、array(原陣列):

const array = [1,2,3,4,5,6]; array.forEach(function(current_value, index, array) { console.log(`At index ${index} in array ${array} the value is ${current_value}`); }); // => undefined

重點是:forEach永遠回傳undefined。它只負責「走訪並執行副作用」,不會產生新的陣列。此外它無法被break中斷——在回呼中return只是跳過目前元素、進入下一個,行為類似continue,這點會在後文「短路遍歷」小節深入說明。

map

如果forEach的「不回傳新陣列」不符合需求,map就是答案:它對每個元素套用函式,收集每次回呼的回傳值,組成並回傳一個全新的陣列,原陣列不受影響。

const array = [1,2,3,4,5,6]; const square = x => Math.pow(x, 2); const squares = array.map(square); console.log(`Original array: ${array}`); console.log(`Squared array: ${squares}`);

map的完整宣告方式與forEach相同:.map(current_value, index, array)。也就是說回呼最多可以接收三個參數,但通常只需要第一個。需要注意的是,如果陣列中存在「空洞」(稀疏陣列),map會跳過空洞並保留洞——如何繞過這個特性,可參考 _posts/en/javascript/2017-03-12-3-array-hacks.md 中提到的Array.apply(null, new Array(N))手法。

reduce

reduce是八種方法中最「進階」也最靈活的一個。原文件引用了 MDN 的定義:

reduce() 方法對累加器和數組中的每個元素(從左到右)應用一個函式,將其減少為一個值。

const array = [1,2,3,4,5,6]; const sum = (x, y) => x + y; const array_sum = array.reduce(sum, 0); console.log(`The sum of array: ${array} is ${array_sum}`);

這個範例把陣列累加成單一數值21。reduce的回呼簽名是(accumulator, currentValue, currentIndex, array),第二個參數0是初始累加值——若省略,第一次回呼會直接以陣列前兩個元素作為累加器與目前值。

倉庫中的 _posts/en/javascript/2016-02-17-reminders-about-reduce-function-usage.md(第 48 號技巧)把reduce玩得更深:初始值不只能是數字,也可以是物件或陣列。該文示範了仿照 ReduxcombineReducers的思路,把多個「部分 reducer」組合成一個「大 reducer」,一次計算出美元、歐元、英鎊、日圓四種貨幣的總價——這證明reduce的累加器可以是任意型別,只要你的 reducer 函式知道怎麼更新它。

filter

filter基於一個「布林函式」過濾陣列:回呼回傳true的元素會被保留,回傳false的被丟棄,最後回傳一個由符合條件的元素組成的新陣列。

const array = [1,2,3,4,5,6]; const even = x => x % 2 === 0; const even_array = array.filter(even); console.log(`Even numbers in array ${array}: ${even_array}`);

輸出為Even numbers in array 1,2,3,4,5,6: 2,4,6。與map一樣,filter也回傳新陣列、不修改原陣列,兩者常搭配使用形成「先過濾、再轉換」的資料管線。

every

every用來測試「每個元素是否都滿足給定條件」。它走訪陣列直到遇到第一個不滿足條件的元素即停止(短路),並回傳true/false:

const array = [1,2,3,4,5,6]; const under_seven = x => x < 7; if (array.every(under_seven)) { console.log('Every element in the array is less than 7'); } else { console.log('At least one element in the array was bigger than 7'); }

由於[1,2,3,4,5,6]全部小於 7,此段會印出Every element in the array is less than 7。every不會回傳陣列,它的角色是「條件判定」。

some

some是every的對偶:測試「至少一個元素是否 match 我們的布林函式」,遇到第一個滿足條件的元素即提前停止並回傳true。

const array = [1,2,3,9,5,6,4]; const over_seven = x => x > 7; if (array.some(over_seven)) { console.log('At least one element bigger than 7 was found'); } else { console.log('No element bigger than 7 was found'); }

陣列中存在9,因此會印出At least one element bigger than 7 was found。some與every的短路特性,讓它們在「只想知道有沒有/是不是」的場景下,比forEach或完整for迴圈更有效率——因為不需要走完整個陣列。

深入原理:forEach 為何無法 break?用 some / every 實作短路遍歷

傳統for迴圈可以break提前結束、continue跳過本次疊代;但forEach的回呼是獨立函式,break/continue語法在回呼內並不合法。這是 _posts/en/javascript/2016-08-17-break-continue-loop-functional.md(第 58 號技巧)處理的核心問題。

首先,forEach的回呼裡return只相當於continue:

[0, 1, 2, 3, 4].forEach(function(val, i) { if (val === 2) { return true; // 只是跳過,迴圈仍會繼續 } console.log(val); // 你的程式碼 }); //> 0, 1, 3, 4

若想在函數式寫法中實現「中斷」,最接近的做法是利用some:回呼回傳true即中斷整個遍歷,且some本身回傳true;回傳false(或任何 falsy 值)則繼續下一個元素。

[0, 1, 2, 3, 4].some(function(val, i) { if (val === 2) { return true; // break } console.log(val); // 你的程式碼 }); //> 0, 1

同樣地,every也可以達到短路效果,只是邏輯相反——every在回呼回傳false時中斷。因此可以歸納出一組對應關係:想要「提早停止並得知結果」,some用return true、every用return false;想要「繼續走訪」,則保持回傳相反的值。這正是把break/continue的語意移植到宣告式 API 上的標準做法。

延伸應用:模數運算打造無限循環陣列

「遍歷陣列」還有一種特殊形態:讓遍歷永遠循環下去。_posts/zh_TW/javascript/2016-05-12-make-easy-loop-on-array.md(第 55 號技巧)以旋轉木馬圖片或播放清單為例,展示了如何用%(模數)運算子讓索引在陣列範圍內循環:

var aList = ['A', 'B', 'C', 'D', 'E']; function make_looper( arr ){ arr.loop_idx = 0; // 回傳目前項目 arr.current = function(){ this.loop_idx = ( this.loop_idx ) % this.length; // 沒有驗證! return arr[ this.loop_idx ]; }; // 增加 loop_idx 並回傳 new current arr.next = function(){ this.loop_idx++; return this.current(); }; // 減少 loop_idx 並回傳 new current arr.prev = function(){ this.loop_idx += this.length - 1; return this.current(); }; } make_looper( aList); aList.current(); // -> A aList.next(); // -> B aList.next(); // -> C aList.next(); // -> D aList.next(); // -> E aList.next(); // -> A aList.pop() ; // -> E aList.prev(); // -> D aList.prev(); // -> C aList.prev(); // -> B aList.prev(); // -> A aList.prev(); // -> D

關鍵在%運算子:2 % 5 = 2、5 % 5 = 0,因此loop_idx遞增到length時會自然歸零;prev反向走訪時則先加上length - 1再取模,避免負索引。實務上有兩點提醒:第一,此寫法是在陣列物件上掛載方法(會修改原陣列),若不想污染陣列,可以改用閉包封裝;第二,範例中的current()註明「沒有驗證」,因為pop()改變長度後,取模結果仍能保持在有效範圍內——這正是模數寫法比if判斷更簡潔的原因。

遍歷方法對照表與選型建議

將八種方法放在一起對照,決策就變得直觀:

方法回傳值能否提前中斷修改原陣列典型用途
while無(依迴圈體而定)可(break/continue/return)否(自行控制)條件式走訪、需要完全自訂控制流
for無可(break/continue/return)否(自行控制)需要索引的經典遍歷
forEachundefined否(return僅等同continue)否對每個元素執行副作用
map新陣列(等長)否否元素逐一轉換
reduce單一值(任意型別)否(可自行設計提早結束)否聚合、累加、組合多個 reducer
filter新陣列(子集)否否依條件篩選元素
every布林值可(回呼回傳false時短路)否驗證所有元素滿足條件
some布林值可(回呼回傳true時短路)否驗證至少一個元素滿足條件

選型時可以依三個問題快速定位:

  1. 需要回傳什麼?需要新陣列選map/filter,需要單一結果選reduce,需要真假值選every/some,只要副作用選forEach,需要索引或完全控制流程選while/for。
  2. 需要中途跳出嗎?宣告式寫法中,some/every是唯一能「短路」的高階方法;若條件複雜,直接回到for搭配break更清晰。
  3. 是否要保留原陣列?上述高階方法皆不修改原陣列,適合函數式風格;while/for是否修改完全取決於迴圈體。

結語

jstips 第 79 號技巧示範了 JavaScript 遍歷陣列的完整光譜:從掌控力最強、程式碼最繁瑣的while/for,到語意明確、易讀易維護的forEach/map/reduce/filter/every/some。搭配倉庫內第 58 號技巧的短路遍歷、第 55 號技巧的模數無限循環、第 48 號技巧的reduce進階組合,你已經具備在各種遍歷需求下選擇正確工具的能力。核心心法是:優先選用語意最貼近需求的高階方法,讓程式碼自己說明意圖;只有在需要break提前跳出、或需要細粒度索引控制時,才回到傳統迴圈。

  • 教程

【免费下载链接】jstips

This is about useful JS tips!

项目地址:https://gitcode.com/gh_mirrors/js/jstips
点击查看免费下载
上一篇:Adobe-GenP 3.0实战指南:5分钟解锁Adobe全系列专业软件
下一篇:3分钟快速还原:Bilibili旧版界面恢复完全指南

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

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

VISA框架:多模态指令数据合成与智能体自我进化工程指南

多模态大模型越来越强&#xff0c;但真正卡住训练进度的&#xff0c;往往不是网络结构&#xff0c;而是高质量的多模态指令数据。人工标注贵、采集周期长、分布覆盖有限。VISA 这篇工作给出的思路是&#xff1a;用智能体自动合成指令数据&#xff0c;并让合成过程自我进化——先…

作者头像 李华
网站建设 2026/10/9 2:07:51

macOS本地大模型管理:GGUF模型盘点与清理实战

如果你已经在一台 Mac 上认真玩过开源大模型&#xff0c;大概率经历过这个瞬间&#xff1a;磁盘空间告急&#xff0c;打开终端翻目录&#xff0c;发现~/.ollama下躺着十几个模型文件&#xff0c;~/models里还散落着一堆.gguf文件&#xff0c;同一个模型有Q4_K_M、Q5_K_S好几个量…

作者头像 李华
网站建设 2026/10/9 2:07:13

点云统计滤波(基于中值距离)

‌效果对比:// ---------- 2. 参数设置 ---------- const float radius 0.1f;// 搜索半径&#xff08;米&#xff09;&#xff1a;决定每个点的邻域大小。// 调试技巧&#xff1a;// - 增大 radius 可在稀疏点云中找到更多邻居&#xff0c;但会增加计算量并可能把不同结构的点…

作者头像 李华
网站建设 2026/10/9 2:06:46

ResNet优化模型实现阿尔茨海默症MRI识别:课程设计实战指南

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

作者头像 李华
网站建设 2026/10/9 2:06:40

在线报名系统实战:Java Web 全栈开发、并发事务与连接池避坑指南

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

作者头像 李华