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

reduce 是數(shù)組的方法,可以對(duì)數(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è)元素開始中剩,依次對(duì)數(shù)組中的每個(gè)元素執(zhí)行回調(diào)函數(shù)忌穿。
? ? 3. 回調(diào)函數(shù)的返回值座位下一次回調(diào)函數(shù)執(zhí)行時(shí)的累計(jì)器的值。
? ? 4. 對(duì)數(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è)對(duì)象

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)換為對(duì)象

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. 將對(duì)象轉(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. 檢查括號(hào)是否匹配

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. 遞歸獲取對(duì)象屬性

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è)簡(jiǎn)單的 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è)元素開始,依次對(duì)數(shù)組中的每個(gè)元素執(zhí)行回調(diào)函數(shù)奢浑,并將返回值作為下一次回調(diào)函數(shù)執(zhí)行時(shí)的累積器的值蛮艰。

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

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

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

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末仍律,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子实柠,更是在濱河造成了極大的恐慌水泉,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,185評(píng)論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件窒盐,死亡現(xiàn)場(chǎng)離奇詭異草则,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)蟹漓,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,652評(píng)論 3 393
  • 文/潘曉璐 我一進(jìn)店門炕横,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人葡粒,你說我怎么就攤上這事份殿。” “怎么了嗽交?”我有些...
    開封第一講書人閱讀 163,524評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵卿嘲,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我夫壁,道長(zhǎng)拾枣,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,339評(píng)論 1 293
  • 正文 為了忘掉前任盒让,我火速辦了婚禮梅肤,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘邑茄。我一直安慰自己凭语,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,387評(píng)論 6 391
  • 文/花漫 我一把揭開白布撩扒。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪搓谆。 梳的紋絲不亂的頭發(fā)上炒辉,一...
    開封第一講書人閱讀 51,287評(píng)論 1 301
  • 那天,我揣著相機(jī)與錄音泉手,去河邊找鬼黔寇。 笑死,一個(gè)胖子當(dāng)著我的面吹牛斩萌,可吹牛的內(nèi)容都是我干的缝裤。 我是一名探鬼主播,決...
    沈念sama閱讀 40,130評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼颊郎,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼憋飞!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起姆吭,我...
    開封第一講書人閱讀 38,985評(píng)論 0 275
  • 序言:老撾萬榮一對(duì)情侶失蹤榛做,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后内狸,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體检眯,經(jīng)...
    沈念sama閱讀 45,420評(píng)論 1 313
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,617評(píng)論 3 334
  • 正文 我和宋清朗相戀三年昆淡,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了锰瘸。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,779評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡昂灵,死狀恐怖避凝,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情倔既,我是刑警寧澤恕曲,帶...
    沈念sama閱讀 35,477評(píng)論 5 345
  • 正文 年R本政府宣布,位于F島的核電站渤涌,受9級(jí)特大地震影響佩谣,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜实蓬,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,088評(píng)論 3 328
  • 文/蒙蒙 一茸俭、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧安皱,春花似錦调鬓、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,716評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽缀踪。三九已至,卻和暖如春虹脯,著一層夾襖步出監(jiān)牢的瞬間驴娃,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,857評(píng)論 1 269
  • 我被黑心中介騙來泰國(guó)打工循集, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留唇敞,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,876評(píng)論 2 370
  • 正文 我出身青樓咒彤,卻偏偏與公主長(zhǎng)得像疆柔,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子镶柱,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,700評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容