js函數式編程(2)-柯裏化
阿新 • • 發佈:2018-09-13
pre 機制 也有 全部 調用 有一個 進一步 代碼 編程
這節開始講的例子都使用簡單的TS來寫,盡量做到和es6差別不大,正文如下
我們在編程中必然需要用到一些變量存儲數據,供今後其他地方調用。而函數式編程有一個要領就是最好不要依賴外部變量(當然允許通過參數傳遞咯),如何解決這個矛盾的問題呢?將函數柯裏化`Curry`就可以了,這種技巧可以讓函數記住一些歷史數據,也就是緩存,怎麽做呢? 說柯裏化之前必須先說一下閉包,因為這是實現柯裏化的方法。
閉包
const fun = () => { let a = 0; return () => { a += 1; return a; }; }; const fa = fun(); console.log(fa()); // 1 console.log(fa()); // 2 console.log(fa()); // 3
每次運行這個函數居然結果不一樣,why?因為`a`是`fun`函數內部變量,而這個變量又被`fun`返回的函數依賴,`fun()`執行後,fa所指向的那個函數(`fun`的返回值)還在依賴著`a`。根據js的垃圾回收機制,只要`fa`存在,那麽`a`就不會被釋放,一直在內存中。 進一步想,既然`a`作為局部變量被依賴著就一直存在,那麽這個局部變量要是參數是不是也有同樣的效果呢,答案是肯定的。
const fun = (a: number) => { return () => { a += 1; return a; }; }; const fa = fun(1); console.log(fa()); // 2 console.log(fa()); // 3 console.log(fa()); // 4
好,閉包就講這麽多。回到柯裏化。
柯裏化
柯裏化由函數閉包實現。我們把上面的例子改一改
const fun = (a: number) => (b: number) => {
return a + b
};
const add2 = fun(2);
console.log(add2(2)); // 4
console.log(add2(3)); // 5
console.log(add2(4)); // 6
`fun(2)`就是`(b) => b+2`,所以`add2(2)`自然是`4`。以上就是柯裏化,參數可以先後傳入,全部傳完才計算。以上是es6或ts的代碼實現,比較簡陋。事實上你完全不必要自己去實現一個函數的柯裏化。可以使用成熟的庫如ramda。ramda庫還包含了很多已經柯裏化的函數。
import { curry } from ‘ramda‘
const fun = curry((a: number, b: number) => {
return a + b
});
const add2 = fun(2);
console.log(add2(2)); // 4
console.log(add2(3)); // 5
console.log(add2(4)); // 6
把一個你要柯裏化的函數,原封不動的給curry函數,返回的就是柯裏化的函數。但要註意函數參數從左往右的順序是依次傳給柯裏化後函數的順序。have fun!
js函數式編程(2)-柯裏化