教程【免费下载链接】jstipsThis 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仍會殘留在外層作用域且閉包捕獲的是同一個變數容易產生預期之外的結果。forEachforEach是 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))手法。reducereduce是八種方法中最「進階」也最靈活的一個。原文件引用了 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 函式知道怎麼更新它。filterfilter基於一個「布林函式」過濾陣列回呼回傳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也回傳新陣列、不修改原陣列兩者常搭配使用形成「先過濾、再轉換」的資料管線。everyevery用來測試「每個元素是否都滿足給定條件」。它走訪陣列直到遇到第一個不滿足條件的元素即停止短路並回傳true/falseconst 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不會回傳陣列它的角色是「條件判定」。somesome是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單一值任意型別否可自行設計提早結束否聚合、累加、組合多個 reducerfilter新陣列子集否否依條件篩選元素every布林值可回呼回傳false時短路否驗證所有元素滿足條件some布林值可回呼回傳true時短路否驗證至少一個元素滿足條件選型時可以依三個問題快速定位需要回傳什麼需要新陣列選map/filter需要單一結果選reduce需要真假值選every/some只要副作用選forEach需要索引或完全控制流程選while/for。需要中途跳出嗎宣告式寫法中some/every是唯一能「短路」的高階方法若條件複雜直接回到for搭配break更清晰。是否要保留原陣列上述高階方法皆不修改原陣列適合函數式風格while/for是否修改完全取決於迴圈體。結語jstips 第 79 號技巧示範了 JavaScript 遍歷陣列的完整光譜從掌控力最強、程式碼最繁瑣的while/for到語意明確、易讀易維護的forEach/map/reduce/filter/every/some。搭配倉庫內第 58 號技巧的短路遍歷、第 55 號技巧的模數無限循環、第 48 號技巧的reduce進階組合你已經具備在各種遍歷需求下選擇正確工具的能力。核心心法是優先選用語意最貼近需求的高階方法讓程式碼自己說明意圖只有在需要break提前跳出、或需要細粒度索引控制時才回到傳統迴圈。赞分享教程【免费下载链接】jstipsThis is about useful JS tips!项目地址https://gitcode.com/gh_mirrors/js/jstips点击查看免费下载相关推荐HuLa 发布流程中的生产配置注入GitHub Actions Secrets 与 production.yaml 实战指南HuLa 发布流程中的生产配置注入GitHub Actions Secrets 与 production.yaml 实战指南 本文档以 HuLa 仓库 doc教程jstips 第 58 期用 .some() 与 .every() 在 JavaScript 函数式遍历中实现 break / continuejstips 第 58 期用 .some 与 .every 在 JavaScript 函数式遍历中实现 break / continue 在 JavaScri教程Functional-Light JavaScript 第 9 章解读用 map / filter / reduce 驾驭列表操作Functional Light JavaScript 第 9 章解读用 map / filter / reduce 驾驭列表操作 导读 本文深入剖析《Fu教程上一篇Adobe-GenP 3.0实战指南5分钟解锁Adobe全系列专业软件下一篇3分钟快速还原Bilibili旧版界面恢复完全指南创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考