10 個(gè)超級實(shí)用的 reduce 使用技巧

reduce 是數(shù)組的方法,可以對數(shù)組中的每個(gè)元素依次執(zhí)行一個(gè)回調(diào)函數(shù),從左到右依次累積計(jì)算出一個(gè)最終的值。其語法為:

arr.reduce(callback(accumulator, currentValue[, index[, array]])[, initialValue])
callback 是每個(gè)元素執(zhí)行的回調(diào)函數(shù),其包含 4 個(gè)參數(shù):
? ? accumulator 累積器,即上一次回調(diào)函數(shù)執(zhí)行的返回值。
? ? currentValue 當(dāng)前元素的值。
? ? index 當(dāng)前元素的下標(biāo)
? ? array 原始數(shù)組
initialValue 是可選的,表示累計(jì)器的初始值
reduce 函數(shù)的執(zhí)行過程如下
? ? 1. 如果沒有提供initialValue,則將數(shù)組的第一個(gè)元素作為累積器的初始值,否則將 initialValue作為累積器的初始值。
? ? 2. 從數(shù)組的第二個(gè)元素開始,依次對數(shù)組中的每個(gè)元素執(zhí)行回調(diào)函數(shù)。
? ? 3. 回調(diào)函數(shù)的返回值座位下一次回調(diào)函數(shù)執(zhí)行時(shí)的累計(jì)器的值。
? ? 4. 對數(shù)組中的每個(gè)元素執(zhí)行完回調(diào)函數(shù)后,reduce函數(shù)返回最后一次回調(diào)函數(shù)的返回值,既最終的累計(jì)值。

1. 計(jì)算數(shù)組中每個(gè)元素出現(xiàn)的次數(shù)

const fruits = ['apple', 'banana', 'apple', 'orange', 'banana', 'apple'];
const count = fruits.reduce((accumulator, currentValue) => {
  accumulator[currentValue] = (accumulator[currentValue] || 0) + 1;
  return accumulator;
}, {});
console.log(count); // Output: { apple: 3, banana: 2, orange: 1 }

2. 拍平嵌套數(shù)組

const nestedArray = [[1, 2], [3, 4], [5, 6]];
const flattenedArray = nestedArray.reduce((accumulator, currentValue) => accumulator.concat(currentValue), []);
console.log(flattenedArray); // Output: [1, 2, 3, 4, 5, 6]

3. 按條件分組

const people = [
  { name: 'Alice', age: 25 },
  { name: 'Bob', age: 30 },
  { name: 'Charlie', age: 35 },
  { name: 'David', age: 25 },
  { name: 'Emily', age: 30 }
];
const groupedPeople = people.reduce((accumulator, currentValue) => {
  const key = currentValue.age;
  if (!accumulator[key]) {
    accumulator[key] = [];
  }
  accumulator[key].push(currentValue);
  return accumulator;
}, {});
console.log(groupedPeople);
// Output: {
//   25: [{ name: 'Alice', age: 25 }, { name: 'David', age: 25 }],
//   30: [{ name: 'Bob', age: 30 }, { name: 'Emily', age: 30 }],
//   35: [{ name: 'Charlie', age: 35 }]
// }

4. 將多個(gè)數(shù)組合并為一個(gè)對象

const keys = ['name', 'age', 'gender'];
const values = ['Alice', 25, 'female'];
const person = keys.reduce((accumulator, currentValue, index) => {
    accumulator[currentValue] = values[index];
    return accumulator;
  }, {});
console.log(person); // Output: { name: 'Alice', age: 25, gender: 'female' }

5. 將字符串轉(zhuǎn)換為對象

const str = 'key1=value1&key2=value2&key3=value3';
const obj = str.split('&').reduce((accumulator, currentValue) => {
  const [key, value] = currentValue.split('=');
  accumulator[key] = value;
  return accumulator;
}, {});
console.log(obj); 
// Output: { key1: 'value1', key2: 'value2', key3: 'value3' }

6. 將對象轉(zhuǎn)換為查詢字符串

const params = { foo: "bar", baz: 42 };
const queryString = Object.entries(params).reduce((acc, [key, value]) => {
  return `${acc}${key}=${value}&`;
}, "?").slice(0, -1);
console.log(queryString); // "?foo=bar&baz=42"

7. 打印斐波那契數(shù)列

const fibonacci = n => {
  return [...Array(n)].reduce((accumulator, currentValue, index) => {
    if (index < 2) {
      accumulator.push(index);
    } else {
      accumulator.push(accumulator[index - 1] + accumulator[index - 2]);
    }
    return accumulator;
  }, []);
};
console.log(fibonacci(10)); // Output: [0, 1, 1, 2, 3, 5, 8, 13, 21, 34]

8. 檢查字符串是否是回文字符串

const str = 'racecar';
const isPalindrome = str.split('').reduce((accumulator, currentValue, index, array) => {
  return accumulator && currentValue === array[array.length - index - 1];
}, true);
console.log(isPalindrome); // Output: true

9. 檢查括號是否匹配

const str = "(()()())";
const balanced = str.split("").reduce((acc, cur) => {
  if (cur === "(") {
    acc++;
  } else if (cur === ")") {
    acc--;
  }
  return acc;
}, 0) === 0;
console.log(balanced); // true

10. 遞歸獲取對象屬性

const user = {
  info: {
    name: "Jason",
    address: { home: "Shaanxi", company: "Xian" },
  },
};
function get(config, path, defaultVal) {
  return path.split('.').reduce((config, name) => config[name], config) || defaultVal;
  return fallback;
}
get(user, "info.name"); // Jason
get(user, "info.address.home"); // Shaanxi
get(user, "info.address.company"); // Xian
get(user, "info.address.abc", "default"); // default

手寫 reduce

可以通過手寫一個(gè)簡單的 reduce函數(shù)來更好地理解它的實(shí)現(xiàn)原理:

function myReduce(arr, callback, initialValue) {
  let accumulator = initialValue === undefined ? arr[0] : initialValue;
  for (let i = initialValue === undefined ? 1 : 0; i < arr.length; i++) {
    accumulator = callback(accumulator, arr[i], i, arr);
  }
  return accumulator;
}

上面的代碼中,myReduce函數(shù)接受 3 個(gè)參數(shù):要執(zhí)行reduce操作的數(shù)組arr、回調(diào)函數(shù)callback和累積器的初始值initialValue。如果沒有提供初始值,則將數(shù)組的第一個(gè)元素作為累積器的初始值。

接下來,在循環(huán)中,如果有initialValue,則從第一個(gè)元素開始遍歷callback,此時(shí)callabck的第二個(gè)參數(shù)是從數(shù)組的第一項(xiàng)開始的;如果沒有initialValue,則從第二個(gè)元素開始遍歷callback,此時(shí)callback的第二個(gè)參數(shù)是從數(shù)組的第二項(xiàng)開始的從數(shù)組的第二個(gè)元素開始,依次對數(shù)組中的每個(gè)元素執(zhí)行回調(diào)函數(shù),并將返回值作為下一次回調(diào)函數(shù)執(zhí)行時(shí)的累積器的值。

最后,myReduce函數(shù)返回最后一次回調(diào)函數(shù)的返回值,即最終的累積值。

這個(gè)簡易的reduce函數(shù)并沒有考慮很多邊界情況和復(fù)雜的應(yīng)用場景,但是可以幫助我們更好地理解reduce函數(shù)的實(shí)現(xiàn)原理。

轉(zhuǎn)自 https://juejin.cn/post/7224043114360225847

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容