關(guān)于譯者:這是一個(gè)流淌著滬江血液的純粹工程:認(rèn)真驱入,是 HTML 最堅(jiān)實(shí)的梁柱卓嫂;分享秀鞭,是 CSS 里最閃耀的一瞥;總結(jié)鸠按,是 JavaScript 中最嚴(yán)謹(jǐn)?shù)倪壿嫛=?jīng)過(guò)捶打磨練,成就了本書的中文版。本書包含了函數(shù)式編程之精髓改淑,希望可以幫助大家在學(xué)習(xí)函數(shù)式編程的道路上走的更順暢。比心炫贤。
譯者團(tuán)隊(duì)(排名不分先后):阿希溅固、blueken、brucecham兰珍、cfanlife、dail询吴、kyoko-df掠河、l3ve、lilins猛计、LittlePineapple唠摹、MatildaJin、冬青奉瘤、pobusama勾拉、Cherry、蘿卜盗温、vavd317藕赞、vivaxy、萌萌卖局、zhouyao
JavaScript 輕量級(jí)函數(shù)式編程
附錄 C:函數(shù)式編程函數(shù)庫(kù)
如果您已經(jīng)從頭到尾通讀了此書斧蜕,請(qǐng)花一分鐘的時(shí)間停下來(lái)回顧一下從第 1 章到現(xiàn)在的收獲。相當(dāng)漫長(zhǎng)的一段旅程砚偶,不是嗎批销?希望您已經(jīng)收獲了大量新知識(shí),并用函數(shù)式的方式思考你的程序染坯。
在本書即將完結(jié)時(shí)均芽,我想給你提供一些關(guān)于使用官方函數(shù)式編程函數(shù)庫(kù)的快速指南。注意這并不是一個(gè)詳細(xì)的文檔单鹿,而是將你在結(jié)束“輕量級(jí)函數(shù)式編程”后進(jìn)軍真正的函數(shù)式編程時(shí)應(yīng)該注意的東西快速梳理一下掀宋。
如果有可能,我建議你不要做重新造輪子這樣的事情。如果你找到了一個(gè)能滿足你需求的函數(shù)式編程函數(shù)庫(kù)布朦,那么用它就對(duì)了囤萤。只有在你實(shí)在找不到合適的庫(kù)來(lái)應(yīng)對(duì)你面臨的問(wèn)題時(shí),才應(yīng)該使用本書提供的輔助實(shí)用函數(shù) —— 或者自己造輪子是趴。
目錄
在本書第 1 章曾列出了一個(gè)函數(shù)式編程庫(kù)的列表涛舍,現(xiàn)在我們來(lái)擴(kuò)展這個(gè)列表。我們不會(huì)涉及所有的庫(kù)(它們之中有許多重復(fù)的內(nèi)容)唆途,但下面這些你應(yīng)該有所關(guān)注:
- Ramda:通用函數(shù)式編程實(shí)用函數(shù)
- Sanctuary:函數(shù)式編程類型 Ramda 伴侶
- lodash/fp:通用函數(shù)式編程實(shí)用函數(shù)
- functional.js:通用函數(shù)式編程實(shí)用函數(shù)
- Immutable:不可變數(shù)據(jù)結(jié)構(gòu)
- Mori:(受到 ClojureScript 啟發(fā))不可變數(shù)據(jù)結(jié)構(gòu)
- Seamless-Immutable:不可變數(shù)據(jù)助手
- tranducers-js:數(shù)據(jù)轉(zhuǎn)換器
- monet.js:Monad 類型
上面的列表只列出了所有函數(shù)式編程庫(kù)的一小部分富雅,并不是說(shuō)沒(méi)有在列表中列出的庫(kù)就不好,也不是說(shuō)列表中列出的就是最佳選擇肛搬,總之這只是 JavaScript 函數(shù)式編程世界中的一瞥没佑。您可以前往這里查看更完整的函數(shù)式編程資源。
Fantasy Land(又名 FL)是函數(shù)式編程世界中十分重要的學(xué)習(xí)資源之一温赔,與其說(shuō)它是一個(gè)庫(kù)蛤奢,不如說(shuō)它是一本百科全書。
Fantasy Land 不是一份為初學(xué)者準(zhǔn)備的輕量級(jí)讀物陶贼,而是一個(gè)完整而詳細(xì)的 JavaScript 函數(shù)式編程路線圖啤贩。為了盡可能提升互通性,F(xiàn)L 已經(jīng)成為 JavaScript 函數(shù)式編程庫(kù)遵循的實(shí)際標(biāo)準(zhǔn)拜秧。
Fantasy Land 與“輕量級(jí)函數(shù)式編程”的概念相反痹屹,它以火力全開的姿態(tài)進(jìn)軍 JavaScript 的函數(shù)式編程世界。也就是說(shuō)枉氮,當(dāng)你的能力超越本書時(shí)志衍,F(xiàn)L 將會(huì)成為你接下來(lái)前進(jìn)的方向。我建議您將其保存在收藏夾中聊替,并在您使用本書的概念進(jìn)行至少 6 個(gè)月的實(shí)戰(zhàn)練習(xí)之后再回來(lái)楼肪。
Ramda (0.23.0)
摘自 Ramda 文檔:
Ramda 函數(shù)自動(dòng)地被柯里化。
Ramda 函數(shù)的參數(shù)經(jīng)過(guò)優(yōu)化佃牛,更便于柯里化淹辞。需要被操作的數(shù)據(jù)往往放在最后提供。
我認(rèn)為合理的設(shè)計(jì)是 Ramda 的優(yōu)勢(shì)之一俘侠。值得注意的是象缀,Ramda 的柯里化形式(似乎大多數(shù)的庫(kù)都是這種形式)是我們?cè)诘?3 章中討論過(guò)的“松散柯里化”。
第 3 章的最后一個(gè)例子 —— 我們定義無(wú)值(point-free)工具函數(shù) printIf()
—— 可以在 Ramda 中這樣實(shí)現(xiàn):
function output(msg) {
console.log( msg );
}
function isShortEnough(str) {
return str.length <= 5;
}
var isLongEnough = R.complement( isShortEnough );
var printIf = R.partial( R.flip( R.when ), [output] );
var msg1 = "Hello";
var msg2 = msg1 + " World";
printIf( isShortEnough, msg1 ); // Hello
printIf( isShortEnough, msg2 );
printIf( isLongEnough, msg1 );
printIf( isLongEnough, msg2 ); // Hello World
與我們?cè)诘?3 章中的實(shí)現(xiàn)相比有幾處不同:
我們使用
R.complement(..)
而不是not(..)
在isShortEnough(..)
周圍新建一個(gè)否定函數(shù)isLongEnough(..)
爷速。使用
R.flip(..)
而不是reverseArgs(..)
函數(shù)央星,值得一提的是,R.flip(..)
僅交換頭兩個(gè)參數(shù)惫东,而reverseArgs(..)
會(huì)將所有參數(shù)反向莉给。在這種情景下毙石,flip(..)
更加方便,所以我們不再需要使用partialRight(..)
或其他投機(jī)取巧的方式進(jìn)行處理颓遏。R.partial(..)
所有的后續(xù)參數(shù)以單個(gè)數(shù)組的形式存在徐矩。因?yàn)?Ramda 使用松散柯里化,因此我們不需要使用
R.uncurryN(..)
來(lái)獲得一個(gè)包含所有參數(shù)的printIf(..)
叁幢。如果我們這樣做了滤灯,就相當(dāng)于使用R.uncurryN(2, ..)
包裹R.partial(..)
進(jìn)行調(diào)用,這是完全沒(méi)有必要的曼玩。
Ramda 是一個(gè)受歡迎的鳞骤、功能強(qiáng)大的庫(kù)。如果你想要在你的代碼中實(shí)踐 FP黍判,從 Ramda 開始是個(gè)不錯(cuò)的選擇豫尽。
Lodash/fp (4.17.4)
Lodash 是整個(gè) JS 生態(tài)系統(tǒng)中最受歡迎的庫(kù)。Lodash 團(tuán)隊(duì)發(fā)布了一個(gè)“FP 友好”的 API 版本 —— "lodash/fp"顷帖。
在第 8 章中美旧,我們討論了合并獨(dú)立列表操作(map(..)
、filter(..)
以及 reduce(..)
)窟她。使用“l(fā)odash/fp”時(shí)陈症,你可以這樣做:
var sum = (x,y) => x + y;
var double = x => x * 2;
var isOdd = x => x % 2 == 1;
fp.compose( [
fp.reduce( sum )( 0 ),
fp.map( double ),
fp.filter( isOdd )
] )
( [1,2,3,4,5] ); // 18
與我們所熟知的 _.
命名空間前綴不同,“l(fā)odash/fp”將 fp.
定義為其命名空間前綴震糖。我發(fā)現(xiàn)一個(gè)很有用的區(qū)別,就是 fp.
比 _.
更容易識(shí)別趴腋。
注意 fp.compose(..)
(在常規(guī) lodash 版本中又名 _.flowRight(..)
)接受一個(gè)函數(shù)數(shù)組吊说,而不是獨(dú)立的函數(shù)作為參數(shù)。
lodash 擁有良好的穩(wěn)定性优炬、廣泛的社區(qū)支持以及優(yōu)秀的性能颁井,是你探索 FP 世界時(shí)的堅(jiān)實(shí)后盾。
Mori (0.3.2)
在第 6 章中蠢护,我們已經(jīng)快速瀏覽了一下 Immutable.js 庫(kù)雅宾,該庫(kù)可能是最廣為人知的不可變數(shù)據(jù)結(jié)構(gòu)庫(kù)了。
讓我們來(lái)看一下另一個(gè)流行的庫(kù):Mori葵硕。Mori 設(shè)計(jì)了一套與眾不同(從表面上看更像函數(shù)式編程)的 API:它使用獨(dú)立的函數(shù)而不直接在值上操作眉抬。
var state = mori.vector( 1, 2, 3, 4 );
var newState = mori.assoc(
mori.into( state, Array.from( {length: 39} ) ),
42,
"meaning of life"
);
state === newState; // false
mori.get( state, 2 ); // 3
mori.get( state, 42 ); // undefined
mori.get( newState, 2 ); // 3
mori.get( newState, 42 ); // "meaning of life"
mori.toJs( newState ).slice( 1, 3 ); // [2,3]
這是一個(gè)指出關(guān)于 Mori 的一些有趣的事情的例子:
使用
vector
而不是list
(你可能會(huì)想用的),主要是因?yàn)槲臋n說(shuō)它的行為更像 JavaScript 中的數(shù)組懈凹。不能像在操作原生 JavaScript 數(shù)組那樣在任意位置設(shè)置值蜀变,在 vector 結(jié)構(gòu)中,這將會(huì)拋出異常介评。因此我們必須使用
mori.into(..)
库北,傳入一個(gè)合適長(zhǎng)度的數(shù)組來(lái)擴(kuò)展 vector 的長(zhǎng)度爬舰。在上例中,vector 有 43 個(gè)可用位置(4 + 39)寒瓦,所以我們可以在最后一個(gè)位置(索引為 42)上寫入"meaning of life"
這個(gè)值情屹。使用
mori.into(..)
創(chuàng)建一個(gè)較大的 vector,再用mor.assoc(..)
根據(jù)這個(gè) vector 創(chuàng)建另一個(gè) vector 的做法聽起來(lái)效率低下垃你。但是蜡镶,不可變數(shù)據(jù)結(jié)構(gòu)的好處在于數(shù)據(jù)不會(huì)進(jìn)行克隆,每次“改變”發(fā)生恤筛,新的數(shù)據(jù)結(jié)構(gòu)只會(huì)追蹤其與舊數(shù)據(jù)結(jié)構(gòu)的不同之處官还。
Mori 受到 ClojureScript 極大的啟發(fā)。如果您有 ClojureScript 編程經(jīng)驗(yàn)毒坛,那您應(yīng)該對(duì) Mori 的 API 感到非常熟悉望伦。由于我沒(méi)有這種編程經(jīng)驗(yàn),因此我感覺(jué) Mori 中的方法名有點(diǎn)奇怪煎殷。
但相比于在數(shù)據(jù)上直接調(diào)用方法屯伞,我真的很喜歡調(diào)用獨(dú)立方法這樣的設(shè)計(jì)。Mori 還有一些自動(dòng)返回原生 JavaScript 數(shù)組的方法豪直,用起來(lái)非常方便劣摇。
總結(jié)
JavaScript 不是作為函數(shù)式編程語(yǔ)言來(lái)特別設(shè)計(jì)的。不過(guò)其自身的確擁有很多對(duì)函數(shù)式編程非常友好基礎(chǔ)語(yǔ)法(例如可作為變量的函數(shù)弓乙、閉包等)末融。本章提及的庫(kù)將使你更方便的進(jìn)行函數(shù)式編程。
有了本書中函數(shù)式編程概念的武裝暇韧,相信你已經(jīng)準(zhǔn)備好開始處理現(xiàn)實(shí)世界的代碼了勾习。找一個(gè)優(yōu)秀的函數(shù)式編程庫(kù)來(lái)用,然后練習(xí)懈玻,練習(xí)巧婶,再練習(xí)。
就是這樣了涂乌。我已經(jīng)將我目前所知道的知識(shí)分享給你了艺栈。我在此正式認(rèn)證您為“JavaScript 輕量級(jí)函數(shù)式編程”程序員!好了骂倘,是時(shí)候結(jié)束我們一起學(xué)習(xí) FP 這部分的“章節(jié)”了眼滤,但我的學(xué)習(xí)之旅還將繼續(xù)。我希望历涝,你也是赵刑!
**【上一章】翻譯連載 | 附錄 B: 謙虛的 Monad-《JavaScript輕量級(jí)函數(shù)式編程》 |《你不知道的JS》姊妹篇 **
[圖片上傳失敗...(image-cd6976-1512962064310)]
iKcamp原創(chuàng)新書《移動(dòng)Web前端高效開發(fā)實(shí)戰(zhàn)》已在亞馬遜般此、京東、當(dāng)當(dāng)開售牵现。
iKcamp官網(wǎng):https://www.ikcamp.com
訪問(wèn)官網(wǎng)更快閱讀全部免費(fèi)分享課程:
《iKcamp出品|全網(wǎng)最新|微信小程序|基于最新版1.0開發(fā)者工具之初中級(jí)培訓(xùn)教程分享》
《iKcamp出品|基于Koa2搭建Node.js實(shí)戰(zhàn)項(xiàng)目教程》
包含:文章科乎、視頻、源代碼
[圖片上傳失敗...(image-292ac3-1512962064310)]