閱讀本篇博客以前須要對JavaScript的閉包有一個很好的瞭解,能夠看一下我以前寫的《前端戰五渣學JavaScript——閉包》javascript
我自認爲你們是在瞭解閉包的狀況下閱讀這篇博客的。前端
最近對什麼都提不起興趣,什麼都不想幹,什麼都不想學,遊戲也不想打。。。哎。。可是最近看了一部國產動畫電影《哪吒之魔童降世》,感受如今國產動畫的水平真是愈來愈高了,很不錯,值得一看哦java
函數柯里化(function currying),把函數作成咖喱味的??其實我初次據說這個詞的時候,感受好高大上啊,音譯,深奧,等我翻看了相關書籍(《JavaScript高級程序設計》)以及一些前輩寫的博客之後,發現原來函數柯里化就是使用閉包返回一個函數閉包
柯里化的函數能夠延遲接收參數,就是好比我一個函數須要接收的參數是兩個,我執行的時候必須接收兩個參數,不然我無法執行啊,是否是,就容易出問題。可是柯里化後的函數,能夠先接收一個函數,而後再接收一個函數,這麼說太生硬了,那咱們就來看一個簡單的例子(也是全網最廣泛的例子)⬇️app
這是普通的函數函數
// 正常咱們聲明函數的時候是這樣的
function 求兩數之和(第一個數, 第二個數) {
return 第一個數 + 第二個數
}
const 和 = 求兩數之和(1, 2);
console.log(`兩數之和爲 ${和}`); // 3
複製代碼
那咱們按照柯里化寫出來的函數是什麼樣的呢
// 理解柯里化的思想
function 求兩數之和(第一個數) {
return function (第二個數) {
return 第一個數 + 第二個數
}
}
// 第一種方法
const 和 = 求兩數之和(1)(2);
console.log(`第一種方法的兩個數之和爲 ${和}`);
// 第二種方法
const 已接收第一個數的求和函數 = 求兩數之和(1);
const 兩個數都已接收的和 = 已接收第一個數的求和函數(2);
console.log(`第二種方法的兩個數之和爲 ${兩個數都已接收的和}`);
複製代碼
從上面的函數對比咱們就能夠發現,柯里化的函數能夠先接收一個函數,而後在咱們須要的傳入第二個參數的時候,咱們再傳入,並執行最終的結果。post
因此咱們能夠動態生成好比第一個參數相同,第二個參數不一樣,或者第二個參數相同,第一個參數不一樣的函數學習
在咱們熟知的《JavaScript高級程序設計》中給出了一個方法,這個方法,可讓咱們把一個原本不支持柯里化的函數,轉化成支持柯里化思想的函數。動畫
function 把函數柯里化(須要柯里化的函數) {
const 調用柯里化時除了函數之外的參數 = Array.prototype.slice.call(arguments, 1);
return function () {
const 後接受的參數 = [...arguments];
const 最終的參數 = [...調用柯里化時除了函數之外的參數, ...後接受的參數];
return 須要柯里化的函數.apply(null, 最終的參數);
}
}
function 求兩數之和(第一個數, 第二個數) {
return 第一個數 + 第二個數
}
const 柯里化的求兩數之和 = 把函數柯里化(求兩數之和, 1);
console.log(
`被柯里化後的函數求的兩數之和爲 ${ 柯里化的求兩數之和(2) }`
); // 被柯里化後的函數求的兩數之和爲 3
複製代碼
咱們發現,咱們能夠單獨寫一個函數,而後把一個普通函數轉化成支持柯里化的函數,可是高級程序設計上提供的這個方法,只能提供兩次調用,什麼意思?咱們來看看lodash
中curry
方法是如何實現的ui
const _ = require('lodash');
function 求三個數之和(第一個數, 第二個數, 第三個數) {
return 第一個數 + 第二個數 + 第三個數
}
const 柯里化後的求三個數之和 = _.curry(求三個數之和);
console.log(柯里化後的求三個數之和(1)(2)(3)); // 6
console.log(柯里化後的求三個數之和(1)(2, 3)); // 6
console.log(柯里化後的求三個數之和(1, 2, 3)); // 6
複製代碼
這下咱們看到,lodash
中對轉化柯里化的處理,咱們能夠任意調用被柯里化的函數,無論參數怎麼傳,只要傳夠三個就行,也無論是分幾回傳。
咱們的需求是什麼?
feature
那咱們先來看看咱們須要轉換的函數⬇️
const 封神榜 = (名字, 寶物, 出生地) => console.log(`我是${出生地}的${名字},我有${寶物}`);
封神榜('哪吒', '乾坤圈', '陳塘關'); // 我是陳塘關的哪吒,我有乾坤圈
複製代碼
看看咱們普通轉化的結果是什麼樣的⬇️
const 封神榜 = 名字 => 寶物 => 出生地 => console.log(`我是${出生地}的${名字},我有${寶物}`);
封神榜('哪吒')('乾坤圈')('陳塘關');
複製代碼
普通轉化的函數,咱們傳參不是很自由,必須穿三次,每次傳一個,那咱們來個牛逼的⬇️
const 封神榜 = (名字, 寶物, 出生地) => console.log(`我是${出生地}的${名字},我有${寶物}`);
const 柯里化 = (須要柯里化的函數, ...參數) => 須要柯里化的函數.length <= 參數.length
? 須要柯里化的函數(...參數)
: (...更多參數) => 柯里化(須要柯里化的函數, ...參數, ...更多參數);
const 柯里化後的封神榜 = 柯里化(封神榜);
柯里化後的封神榜('哪吒', '乾坤圈', '陳塘關'); // 我是陳塘關的哪吒,我有乾坤圈
柯里化後的封神榜('孫悟空')('金箍魯棒')('花果山'); // 我是花果山的孫悟空,我有金箍魯棒
柯里化後的封神榜('雷震子', '黃金棍')('終南山玉柱洞'); // 我是終南山玉柱洞的雷震子,我有黃金棍
柯里化後的封神榜()()()()()()()()('姜子牙', '打神鞭', '崑崙山'); // 我是崑崙山的姜子牙,我有打神鞭
複製代碼
看,如今咱們實現的柯里化函數已經基本知足咱們剛纔提的需求了
固然,有柯里化就有反柯里化,可是我以爲沒什麼必要,我既然都已經柯里化了,柯里化後的函數固然支持非柯里化函數的傳參方式,可是有興趣的小夥伴仍是能夠了解一下的
其實函數柯里化這個概念,可能咱們以前沒有據說過,可是工做或者學習中咱們可能或多或少接觸過這種方式,只是不知道這麼寫就是柯里化,這個函數就是柯里化函數。
柯里化函數這種方式方法仍是很實用的,在平常開發過程當中仍是會遇到須要這種需求的地方。
我是前端戰五渣,一個前端界的小學生。