摘要:reduce() 是 JavaScript 數組方法中最強大但也最常被誤解的方法之一。它能夠將數組元素"縮減"為單個值,這個值可以是數字、字符串、對象甚至另一個數組。本文將深入探討 r...
reduce() 是 JavaScript 數組方法中最強大但也最常被誤解的方法之一。它能夠將數組元素"縮減"為單個值,這個值可以是數字、字符串、對象甚至另一個數組。本文將深入探討 reduce() 的工作原理、使用場景和最佳實踐。
1. reduce() 基礎語法
reduce() 方法的基本語法如下:
array.reduce(callback(accumulator, currentValue[, index[, array]])[, initialValue])
參數說明:
callback:執行數組中每個值的函數,包含四個參數:
accumulator:累計器,累積回調的返回值
currentValue:數組中正在處理的當前元素
index(可選):當前元素的索引
array(可選):調用reduce的數組
initialValue(可選):作為第一次調用callback時的第一個參數的值
2. 工作原理
reduce() 方法對數組中的每個元素按順序執行一個"reducer"函數,每一次調用都將上一次調用的結果作為下一次調用的第一個參數傳入,最終匯總為單個返回值。
執行過程示例
const numbers = [1, 2, 3, 4]; const sum = numbers.reduce((acc, curr) => acc + curr, 0); // 執行步驟: // 第一次調用: acc = 0, curr = 1 => 返回 1 // 第二次調用: acc = 1, curr = 2 => 返回 3 // 第三次調用: acc = 3, curr = 3 => 返回 6 // 第四次調用: acc = 6, curr = 4 => 返回 10 // 最終結果: 10
3. 常見使用場景
3.1 數組求和
const numbers = [1, 2, 3, 4]; const sum = numbers.reduce((acc, num) => acc + num, 0); console.log(sum); // 10
3.2 計算平均值
const numbers = [1, 2, 3, 4]; const average = numbers.reduce((acc, num, index, arr) => { acc += num; if (index === arr.length - 1) { return acc / arr.length; } return acc; }, 0); console.log(average); // 2.5
3.3 數組元素計數
const fruits = ['apple', 'banana', 'apple', 'orange', 'banana', 'apple']; const count = fruits.reduce((acc, fruit) => { acc[fruit] = (acc[fruit] || 0) + 1; return acc; }, {}); console.log(count); // { apple: 3, banana: 2, orange: 1 }
3.4 數組扁平化
const nestedArrays = [[1, 2], [3, 4], [5, 6]]; const flattened = nestedArrays.reduce((acc, arr) => acc.concat(arr), []); console.log(flattened); // [1, 2, 3, 4, 5, 6]
3.5 對象屬性求和
const products = [ { name: 'Laptop', price: 1000 }, { name: 'Phone', price: 500 }, { name: 'Tablet', price: 300 } ]; const totalPrice = products.reduce((acc, product) => acc + product.price, 0); console.log(totalPrice); // 1800
4. 高級用法
4.1 管道函數組合
const pipe = (...functions) => input => functions.reduce((acc, fn) => fn(acc), input); const add5 = x => x + 5; const multiply2 = x => x * 2; const subtract3 = x => x - 3; const transform = pipe(add5, multiply2, subtract3); console.log(transform(10)); // ((10 + 5) * 2) - 3 = 27
4.2 實現數組的map和filter
// 實現map const map = (arr, fn) => arr.reduce((acc, val) => [...acc, fn(val)], []); // 實現filter const filter = (arr, fn) => arr.reduce( (acc, val) => fn(val) ? [...acc, val] : acc, [] );
4.3 按屬性分組
const people = [ { name: 'Alice', age: 21 }, { name: 'Bob', age: 21 }, { name: 'Charlie', age: 22 } ]; const groupedByAge = people.reduce((acc, person) => { const age = person.age; if (!acc[age]) { acc[age] = []; } acc[age].push(person); return acc; }, {}); console.log(groupedByAge); /* { 21: [{ name: 'Alice', age: 21 }, { name: 'Bob', age: 21 }], 22: [{ name: 'Charlie', age: 22 }] } */
5. 注意事項
1.初始值的重要性:如果不提供初始值,reduce會使用數組的第一個元素作為初始值并從第二個元素開始迭代。這在空數組上調用時會出錯誤。
[].reduce((acc, val) => acc + val); // TypeError [].reduce((acc, val) => acc + val, 0); // 0
2.性能考慮:在大型數組上,頻繁使用展開運算符(...)或concat創建新數組可能會影響性能。在這種情況下,考慮使用push修改現有數組。
3.可讀性:復雜的reduce操作可能會降低代碼可讀性。如果邏輯變得復雜,考慮使用傳統的循環或其他數組方法。