溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

javascript中的reduce fold unfold怎么用

發(fā)布時間:2021-05-07 14:02:14 來源:億速云 閱讀:138 作者:小新 欄目:開發(fā)技術

這篇文章給大家分享的是有關javascript中的reduce fold unfold怎么用的內容。小編覺得挺實用的,因此分享給大家做個參考,一起跟隨小編過來看看吧。

JavaScript的作用是什么

1、能夠嵌入動態(tài)文本于HTML頁面。2、對瀏覽器事件做出響應。3、讀寫HTML元素。4、在數(shù)據(jù)被提交到服務器之前驗證數(shù)據(jù)。5、檢測訪客的瀏覽器信息。6、控制cookies,包括創(chuàng)建和修改等。7、基于Node.js技術進行服務器端編程。

fold(reduce)

說說reduce吧, 很喜歡這個函數(shù),節(jié)省了不少代碼量,而且有一些聲明式的雛形了,一些常見的工具函數(shù),flatten,deepCopy,mergeDeep等用reduce實現(xiàn)的很優(yōu)雅簡潔。reduce也稱為fold,本質上就是一個折疊數(shù)組的過程,把數(shù)組中的多個值經(jīng)過運算變成一個值,每次運算都會有一個函數(shù)處理,這個函數(shù)就是reduce的核心元素,稱之為reducer,reducer函數(shù)是個2元函數(shù),返回1個單值,常見的add函數(shù)就是reducer

const addReducer = (x, y) => x + y;

這個add函數(shù)就是一個reducer,最常見的用法就是結合數(shù)組的reduce方法來用

[1, 2, 3, 4, 5].reduce(addReducer, 0) // 15

為了更好的理解reduce,下面用不同的思路實現(xiàn)一遍這個函數(shù)

使用for...of

const reduce = (f, init, arr) => {
  let acc = init;
  for (const item of arr) {
    acc = f(acc, item);
  }
  return acc
}
// 執(zhí)行
reduceFor(addReducer, 0, [1, 2, 3, 4, 5])  // 15

使用while循環(huán)

reduce = (f, init, arr) => {
  let acc = init;
  let current;
  let i = 0;
  while ((current = arr[i++])) {
    acc = f(acc, current);
  }
  return acc;
}

// 執(zhí)行
reduceFor(addReducer, 0, [1, 2, 3, 4, 5])  // 15

更像fold的實現(xiàn)

上面的實現(xiàn)也都好理解,但好像沒有體現(xiàn)出來折疊(fold)這個過程,折疊應該是對數(shù)組的層層擠壓操作,上面的實現(xiàn)數(shù)組和邏輯其實是分開了,而且也引入了比較多的中間變量,雖然是在內部沒有副作用吧。
其實換個思路想一下,如果把狀態(tài)通過參數(shù)來傳遞,就可以更好的體現(xiàn)fold的過程,這里的參數(shù)是值是指逐漸變化的數(shù)組和計算值,并可以盡可能的做到無狀態(tài),真正純函數(shù)的實現(xiàn)是沒有表達式,只有語句的,這個可以用遞歸做到。下面的實現(xiàn)是用尾遞歸實現(xiàn)的reduce,可以在實現(xiàn)的過程中就看出數(shù)組和計算值是怎樣變化的。非常符合fold這個稱謂

function reduce(f, init, arr) {
  if (arr.length === 0) return init;
  const [head, ...rest] = arr;
  return reduceRecursion(f, f(init, head), rest);
}

// 執(zhí)行
reduceFor(addReducer, 0, [1, 2, 3, 4, 5])  // 15

unfold

fold反過來就是unfold,unfold顧名思義就是根據(jù)一個反過來的reducer,來生成一系列的值。此時這個如果說原來的reducer實現(xiàn)類似于(a, b) -> c,那反過來就是c -> [a, b], 生成序列是一個很基本的操作,但就是這個基本的操作,也有很多實現(xiàn)的思路,在介紹unfold之前,看一下實現(xiàn)序列的其他方法,最后來做一個對比。

序列的實現(xiàn)

range(0, 100, 5)

期待結果

[0, 5, 10, ... 95]

數(shù)組實現(xiàn)

這個就不多說了,大家應該都知道。

range = (first, last, step) => {
  const n = (last - first) / step + 1;
  return Array.from({ length: n - 1 })
            .map((_, index) => first + index * step);
}
// 也可以使用from的第二個參數(shù)
// Array.from({ length: n }, (_, i) => first + i * step);

生成器實現(xiàn)

生成序列還有一個利器,那就是generator,生成器生成器,就是用來生成數(shù)據(jù)的。generator返回一個迭代器,也很容易生成序列

function* range(first, last, step) {
  let acc = first;
  while (acc < last) {
    yield acc;
    acc = acc + step;
  }
}
[...range(0, 100, 5)]

兩者相比,generator更注重生成的過程,Array注重數(shù)據(jù)變化的過程。

unfold實現(xiàn)

在實現(xiàn)unfold之前,首先梳理一下實現(xiàn)思路,和fold一樣,也是用遞歸,且要在實現(xiàn)的過程中看到對應數(shù)據(jù)的變化。大體過程如下

0 -> [0, 5]

5 -> [5, 10]

10 -> [10, 15]

15 -> [15, 20]

...

90 -> [90, 95]

95 -> [95, 100]

可以看出過程恰恰是fold反過來,符合c -> [a, b]因為初始值肯定為一個數(shù)組,所以unfold只需要兩個參數(shù),實現(xiàn)如下。

function unfold(f, init) {
  const g = (f, next, acc) => {
    const result = f(next);
    const [head, last] = result || [];
    console.log(last);
    return result ? g(f, last, acc.concat(head)) : acc;
  };
  return g(f, init, []);
}

range = R.curry((first, last, step) =>
  unfold(next => next < last && [next, next + step], 0)
)

// 執(zhí)行
range(0, 100, 5)

感謝各位的閱讀!關于“javascript中的reduce fold unfold怎么用”這篇文章就分享到這里了,希望以上內容可以對大家有一定的幫助,讓大家可以學到更多知識,如果覺得文章不錯,可以把它分享出去讓更多的人看到吧!

向AI問一下細節(jié)

免責聲明:本站發(fā)布的內容(圖片、視頻和文字)以原創(chuàng)、轉載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權內容。

AI