<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          進(jìn)大廠之必會(huì)的函數(shù)柯里化(Currying)

          共 3933字,需瀏覽 8分鐘

           ·

          2021-03-14 07:56

          深入了解函數(shù)柯里化

          curry是一種處理函數(shù)的高級(jí)技術(shù)。它不僅在JavaScript中使用,也在其他語言中使用。

          套用是函數(shù)的一種轉(zhuǎn)換,將函數(shù)從可調(diào)用的f(a, b, c)轉(zhuǎn)換為可調(diào)用的f(a)(b)(c)。

          curry不調(diào)用函數(shù)。它只是改變了它。

          讓我們先看一個(gè)例子,以便更好地理解我們正在討論的內(nèi)容,然后看實(shí)際應(yīng)用程序。

          我們將創(chuàng)建一個(gè)輔助函數(shù)curry(f),它執(zhí)行對(duì)兩個(gè)參數(shù)fcurry。換句話說,對(duì)于兩個(gè)參數(shù)f(a, b)curry(f)將其轉(zhuǎn)換為一個(gè)以f(a)(b)的方式運(yùn)行的函數(shù):

          function curry(f) { // curry(f) does the currying transform
          return function(a) {
          return function(b) {
          return f(a, b);
          };
          };
          }

          // usage
          function sum(a, b) {
          return a + b;
          }

          let curriedSum = curry(sum);

          alert( curriedSum(1)(2) ); // 3

          如您所見,實(shí)現(xiàn)很簡單:它只是兩個(gè)包裝器。

          curry(func)的結(jié)果是一個(gè)包裝函數(shù)(a)。

          當(dāng)像curriedSum(1)那樣調(diào)用時(shí),參數(shù)被保存在詞法環(huán)境中,并返回一個(gè)新的包裝器函數(shù)(b)。

          然后用2作為參數(shù)調(diào)用這個(gè)包裝器,并將調(diào)用傳遞給原始的sum。

          更高級(jí)的套用實(shí)現(xiàn),例如lodash庫中,返回一個(gè)允許函數(shù)被正?;虿糠终{(diào)用的包裝器:

          function sum(a, b{
            return a + b;
          }

          let curriedSum = _.curry(sum); // using _.curry from lodash library

          alert( curriedSum(12) ); // 3, still callable normally
          alert( curriedSum(1)(2) ); // 3, called partially

          為了理解這些好處,我們需要一個(gè)有價(jià)值的現(xiàn)實(shí)例子。

          例如,我們有日志功能log(date、importance、message)來格式化和輸出信息。在實(shí)際的項(xiàng)目中,這樣的函數(shù)有很多有用的特性,比如通過網(wǎng)絡(luò)發(fā)送日志,這里我們只使用alert:

          function log(date, importance, message{
            alert(`[${date.getHours()}:${date.getMinutes()}] [${importance}${message}`);
          }

          對(duì)其進(jìn)行函數(shù)柯里化

          log = _.curry(log);

          日志正常工作后:

          log(new Date(), "DEBUG""some debug"); // log(a, b, c)

          也可以使用 柯里化

          log(new Date())("DEBUG")("some debug"); // log(a)(b)(c)

          現(xiàn)在我們可以很容易地為當(dāng)前日志創(chuàng)建一個(gè)方便的函數(shù):

          // logNow will be the partial of log with fixed first argument
          let logNow = log(new Date());

          // use it
          logNow("INFO""message"); // [HH:mm] INFO message

          現(xiàn)在logNow是帶有固定第一個(gè)參數(shù)的日志,換句話說就是“部分應(yīng)用函數(shù)”或簡稱為“partial”。

          我們可以更進(jìn)一步,為當(dāng)前調(diào)試日志創(chuàng)建一個(gè)方便的函數(shù):

          let debugNow = logNow("DEBUG");

          debugNow("message"); // [HH:mm] DEBUG message

          所以:

          curry后我們沒有丟失任何東西:log仍然可以正常調(diào)用。

          我們可以很容易地生成部分函數(shù),比如今天的日志。

          進(jìn)階的柯里化實(shí)現(xiàn)

          如果您想了解更多細(xì)節(jié),這里是我們可以在上面使用的多參數(shù)函數(shù)的“高級(jí)”curry實(shí)現(xiàn)。

          很短:

          function curry(func{

            return function curried(...args{
              if (args.length >= func.length) {
                return func.apply(this, args);
              } else {
                return function(...args2{
                  return curried.apply(this, args.concat(args2));
                }
              }
            };

          }

          案例

          function sum(a, b, c{
            return a + b + c;
          }

          let curriedSum = curry(sum);

          alert( curriedSum(123) ); // 6, still callable normally
          alert( curriedSum(1)(2,3) ); // 6, currying of 1st arg
          alert( curriedSum(1)(2)(3) ); // 6, full currying

          新的curry看起來可能很復(fù)雜,但實(shí)際上很容易理解。

          curry(func)調(diào)用的結(jié)果是這樣的包裝器curry:

          // func is the function to transform
          function curried(...args{
            if (args.length >= func.length) { // (1)
              return func.apply(this, args);
            } else {
              return function(...args2// (2)
                return curried.apply(this, args.concat(args2));
              }
            }
          };

          當(dāng)我們運(yùn)行它時(shí),有兩個(gè)if執(zhí)行分支:

          如果傳入的args count與原始函數(shù)的定義(function.length)相同或更多,則只需使用function.apply將調(diào)用傳遞給它。

          否則,得到一個(gè)部分:我們還沒有調(diào)用func。相反,將返回另一個(gè)包裝器,它將重新應(yīng)用curry,同時(shí)提供以前的參數(shù)和新的參數(shù)。

          然后,如果我們?cè)俅握{(diào)用它,我們將得到一個(gè)新的部分(如果沒有足夠的參數(shù)),或者最終得到結(jié)果。


          瀏覽 54
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  人人做人人爱免费的视频 | 亚洲无码一区二区电影 | 色伊人大香蕉 | 99视频在线播放观看精品 | 99久久久久久久 |