柯里化將多引數函數轉換為一元(單引數)函數。【相關推薦:】
柯里化函數一次接受多個引數。所以如果你有
greet = (greeting, first, last) => `${greeting}, ${first} ${last}`; greet('Hello', 'Bruce', 'Wayne'); // Hello, Bruce Wayne
可以寫成這種形式
curriedGreet = curry(greet); curriedGreet('Hello')('Bruce')('Wayne'); // Hello, Bruce Wayne
正確的使用「柯里化」是因為某些curry
函數在使用上更加靈活。Currying 在理論上很棒,但是在 JavaScript 中為每個引數呼叫一個函數會很累。
Ramda 的 curry
函數可以讓你curriedGreet
像這樣呼叫:
// greet requires 3 params: (greeting, first, last) // these all return a function looking for (first, last) curriedGreet('Hello'); curriedGreet('Hello')(); curriedGreet()('Hello')()(); // these all return a function looking for (last) curriedGreet('Hello')('Bruce'); curriedGreet('Hello', 'Bruce'); curriedGreet('Hello')()('Bruce')(); // these return a greeting, since all 3 params were honored curriedGreet('Hello')('Bruce')('Wayne'); curriedGreet('Hello', 'Bruce', 'Wayne'); curriedGreet('Hello', 'Bruce')()()('Wayne');
請注意,你可以選擇一次性給出多個引數。此實現在編寫程式碼時更有用。
如上所示,你可以在沒有引數的情況下永遠呼叫此函數,並且它將始終返回一個需要剩餘引數的函數。
const curry = (f, arr = []) => (...args) => ((a) => (a.length === f.length ? f(...a) : curry(f, a)))([...arr, ...args]);
讓我們一起重構和欣賞它。
我還在debugger
Chrome 開發人員工具中新增了一些語句來檢查它。
curry = (originalFunction, initialParams = []) => { debugger; return (...nextParams) => { debugger; const curriedFunction = (params) => { debugger; if (params.length === originalFunction.length) { return originalFunction(...params); } return curry(originalFunction, params); }; return curriedFunction([...initialParams, ...nextParams]); }; };
貼上greet
並curry
進入您的控制檯。然後進入curriedGreet = curry(greet)
並開始瘋狂。
檢查我們看到的兩個引數,originalFunction
並且greet
預設initialParams
為空陣列,因為我們沒有提供它。移動到下一個斷點,哦等等……就是這樣。
是的!curry(greet)
只返回一個需要 3 個以上引數的新函數。在控制檯中輸入curriedGreet
以檢視我在說什麼。
當你玩完這個之後,讓我們變得更瘋狂一點,然後做sayHello = curriedGreet('Hello')
.
在繼續之前,在控制檯中輸入originalFunction
和。initialParams
請注意,即使我們在一個全新的函數中,我們仍然可以存取這兩個引數?這是因為從父函數返回的函數享有其父函數的作用域。
在父函數傳遞之後,他們將引數留給孩子使用。有點像現實生活中的繼承。
curry
最初給出originalFunction
,initialParams
然後返回一個「子」函數。這兩個變數還沒有被處理掉,因為也許那個孩子需要它們。如果他不這樣做,那麼這個範圍就會被清理乾淨,因為當沒有人提到你時,那就是你真正死去的時候。
檢查nextParams
並看到它是['Hello']
……一個陣列?但我以為我們說curriedGreet(‘Hello’)
,不是curriedGreet(['Hello'])
!
正確:我們呼叫curriedGreet
了 with 'Hello'
,但是多虧了rest 語法,我們變成 'Hello'
了['Hello']
.
curry
是一個通用函數,可以提供 1、10 或 10,000,000 個引數,因此它需要一種方法來參照所有引數。使用類似的 rest 語法捕獲一個陣列中的每個引數,使curry
' 的工作更容易。
讓我們跳到下debugger
一條語句。
您可能已經注意到第 12 行實際上在debugger
第 6 行的語句之前執行。如果不是,請仔細檢視。我們的程式在第 5 行定義了一個呼叫函數curriedFunction
,在第 12 行使用它,然後我們debugger
在第 6 行點選了該語句。curriedFunction
呼叫的是什麼?
[...initialParams, ...nextParams];
呸呸呸。檢視params
第 5 行,您會看到['Hello']
. 兩者initialParams
和都是陣列,所以我們使用方便的擴充套件運運算元nextParams
將它們展平並組合成一個陣列。
這就是好事發生的地方。
第 7 行說「如果params
和originalFunction
長度相同,請greet
使用我們的引數呼叫,我們就完成了。」 這使我想起…
這就是curry
它的魔力!這就是它決定是否要求更多引數的方式。
在 JavaScript 中,函數的 .length
屬性告訴你它需要多少個引數。
greet.length; // 3 iTakeOneParam = (a) => {}; iTakeTwoParams = (a, b) => {}; iTakeOneParam.length; // 1 iTakeTwoParams.length; // 2複製程式碼
如果我們提供的和預期的引數匹配,我們很好,只需將它們交給原始函數並完成工作!
但是在我們的例子中,引數和函數長度是不一樣的。我們只提供了‘Hello’
,所以params.length
是 1,並且originalFunction.length
是 3 因為greet
需要 3 個引數:greeting, first, last
。
好吧,由於該if
語句的計算結果為false
,程式碼將跳到第 10 行並重新呼叫我們的主curry
函數。它重新接收greet
,這一次,'Hello'
並重新開始瘋狂。
這就是遞迴,我的朋友們。
curry
本質上是一個無限迴圈的自呼叫,引數飢渴的函數,直到他們的客人滿了才會休息。熱情好客。
與以前相同initialParams
的引數,除了['Hello']
這次。再次跳過以退出迴圈。在控制檯中輸入我們的新變數,sayHello
. 這是另一個函數,仍然期待更多引數,但我們正在變得更加溫暖......
讓我們把火調大sayHelloToJohn = sayHello('John')
。
我們又在第 4 行了,而且nextParams
是['John']
。跳到第 6 行的下一個偵錯程式並檢查params
:它是['Hello', 'John']
!?
因為請記住,第 12 行說「嘿curriedFunction
,他'Hello'
上次和‘John’
這次都給了我。把他們兩個都帶進這個陣法[...initialParams, ...nextParams]
。」
現在curriedFunction
再次將length
這些params
與進行比較originalFunction
,因為2 < 3
我們移動到第 10 行並curry
再次呼叫!當然,我們傳遞greet
了我們的 2 個引數,['Hello', 'John']
我們已經很接近了,讓我們完成這一切,並得到完整的問候!
sayHelloToJohnDoe = sayHelloToJohn('Doe')
我想我們知道接下來會發生什麼。
greet
得到他的引數,curry
停止迴圈,我們收到了我們的問候:Hello, John Doe
.
多玩一些這個功能。嘗試一次提供多個引數或不提供引數,隨心所欲地瘋狂。curry
檢視在返回預期輸出之前必須遞迴多少次。
curriedGreet('Hello', 'John', 'Doe'); curriedGreet('Hello', 'John')('Doe'); curriedGreet()()('Hello')()('John')()()()()('Doe');
【相關視訊教學推薦: 】
以上就是一文快速瞭解JS中的柯里化(Currying)的詳細內容,更多請關注TW511.COM其它相關文章!