JavaScript 陣列方法整理:forEach、map、filter、find、some、every、sort、reduce
整理八個最常用的陣列方法差異——會不會產生新陣列、會不會動到原始資料、回傳的是單一元素還是整個陣列還是布林值。用同一份商品清單示範,並修正原始筆記裡 sort 比較函式回傳布林值而不是數字的常見錯誤。
W
這幾個陣列方法名字很像,但回傳的東西、會不會動到原始資料完全不同,整理一份對照,用同一份商品清單示範。
const books = [
{ name: '這樣思考,人生就不一樣', price: 320, discount: 0.9 },
{ name: '原子習慣', price: 360, discount: 0.85 },
{ name: '被討厭的勇氣', price: 300, discount: 0.79 },
];
forEach:對每個元素執行動作
books.forEach((book) => {
book.total = book.price * book.discount; // 直接改變原本的物件
console.log(book.total);
});
單純跑一次迴圈,不會回傳新陣列(回傳值是 undefined),如果在迴圈裡改動了元素本身的屬性(元素是物件時),會直接影響原陣列——因為陣列裡存的是物件的參考,改物件屬性等於改到原本那份資料。
map:執行結果存到新陣列
const numbers = [1, 2, 3, 4, 5, 6];
const squared = numbers.map((num) => num * num);
console.log(squared); // [1, 4, 9, 16, 25, 36]
console.log(numbers); // [1, 2, 3, 4, 5, 6] ← 原陣列不變
保留原陣列,回傳一份新陣列,常用在把一批物件轉換、抽取、計算成另一種形狀:
const summary = books.map((book) => ({
name: book.name,
total: book.price * book.discount,
}));
filter:留下符合條件的元素
const numbers = [1, 2, 3, 4, 5, 6];
const bigNumbers = numbers.filter((num) => num > 3);
console.log(bigNumbers); // [4, 5, 6]
依函式回傳的布林值決定要不要把元素留下來,保留原陣列,回傳一份新陣列,扮演「篩選閘門」的角色——回傳 true 的元素才會出現在結果裡。
find:找到第一個符合條件的元素
const dnaList = ['ATC', 'AGC', 'AAA', 'TTG'];
const found = dnaList.find((dna) => dna.indexOf('TG') > -1);
console.log(found); // 'TTG'
跟 filter 的差別:find 回傳的是單一元素本身,不是陣列,而且只回傳第一個符合條件的,找到就停止繼續找,沒有符合條件的元素則回傳 undefined。
some:判斷是否「有」元素符合條件
const numbers = [1, 2, 3, 4, 5, 6];
const hasEven = numbers.some((num) => num % 2 === 0);
console.log(hasEven); // true,只要有一個是偶數就成立
回傳布林值,只要有一個元素符合條件就回傳 true,適合「大概知道有沒有,不需要知道確切是哪一筆」的情境——例如「這些文章裡有沒有含某個關鍵字」「會員裡有沒有人不符合資格」。
every:判斷是否「全部」元素都符合條件
const numbers = [1, 2, 3, 4, 5, 6];
const allEven = numbers.every((num) => num % 2 === 0);
console.log(allEven); // false,因為 1、3、5 不是偶數
每一個元素都符合條件才回傳 true,任何一個不符合就整體回傳 false。
sort:依比較函式排序
const members = [{ year: 27 }, { year: 14 }, { year: 50 }];
members.sort((a, b) => a.year - b.year);
console.log(members); // [{year:14}, {year:27}, {year:50}]
比較函式一定要回傳數字,不能回傳布林值——這是最容易寫錯的地方:(a, b) => a.year > b.year 回傳的是 true/false,雖然多數瀏覽器引擎會把 true 當成 1、false 當成 0 處理、勉強排得出一個看起來正確的順序,但這不是規格保證的行為,遇到需要穩定排序(相同值的元素要保持原本的相對順序)或某些特殊資料分佈時可能出錯。正確的寫法是回傳兩者的差值:a - b 是由小到大,b - a 是由大到小。
sort() 也要記得它是原地排序,會直接修改原陣列,這點在之前寫過的 sort/filter 筆記裡有更完整的說明。
reduce:把整個陣列縮減成一個值
const books2 = [{ price: 10 }, { price: 20 }, { price: 30 }];
const total = books2.reduce((sum, book) => sum + book.price, 0);
console.log(total); // 60
reduce 吃兩個參數:處理函式跟初始值(範例裡的 0)。處理函式本身也吃兩個參數:累加器(上一輪執行完的結果,第一輪則是初始值)跟目前的元素。可以想成「帶了記憶(暫存器)的 forEach」,除了加總,也常用在分類歸群、把陣列接成字串這類「多筆資料合併成一個結果」的情境。
對照表
| 方法 | 回傳什麼 | 動到原陣列嗎 |
|---|---|---|
forEach | undefined | 元素是物件時,改屬性會動到原資料 |
map | 新陣列(一對一轉換) | 不會 |
filter | 新陣列(篩選後的子集) | 不會 |
find | 單一元素(或 undefined) | 不會 |
some | 布林值 | 不會 |
every | 布林值 | 不會 |
sort | 排序後的原陣列 | 會,原地排序 |
reduce | 累加後的單一結果 | 不會 |
後來又多了幾個好用的陣列方法,整理在《後來新增的陣列方法:at、findLast、toSorted 這一批》。