摘要:不純的函數充滿的不確定性,在函數式編程中要盡量避免它。在以后的函數式編程中還會不斷的遇見它的。
一.為什么需要柯里化(curry函數)
1.先簡單的介紹一下純函數
在函數式編程中純函數是其最基本的思想,所謂純函數就是一個相對不受外界影響(之所以說相對,是因為有的時候需要和外界溝通,函數沒法保持所謂真正的純,但后面會有方法來解決).在高中數學中都學過,函數是一種映射關系,在y=f(x)這個函數式中,每一個x都有一個與之對應的y值與它唯一對應。
說了這么多好像還是不是很明白,那就來個簡單的例子:
//不純的 var num=18 function foo1(enter) { if (enter>18) { console.log("wow") } } //純的 function foo2(enter) { var num=18 if (enter>18) { console.log("wow") } }
兩個函數實現的效果其實是一樣的,但第一個函數不純,第二個函數才是真的純函數,它將num定義在函數體內,外界無法直接獲取num,也無法改變它,相當于打雷天縮到了被窩,外面雷再大也跟我沒關系了。
第一個函數之所以不純是因為,它引用了函數體外的一個變量num,一旦你進行了外部引用,那這個函數的輸出就不確定了。一旦num被改變了,那這個函數就不會按照你希望的執行下去了。不純的函數充滿的不確定性,在函數式編程中要盡量避免它。
純函數中還有很多的好處,再此就不展開討論了,以后有機會再詳細的說說。
2.純函數的一個使用場景
var add=x=>(y=>x+y)//為了更貼切函數式編程,這里用了ES6的寫法,等價于下面的函數 // var add=function (x) { // return function(y) { // return x+y // } // } var add2=add(2) console.log(add2(1)) //3
這里使用閉包的方法,在add函數體內返回的匿名函數中有這樣一句話:return x+y
它在匿名函數中保持著對x的引用,即使在垃圾回收中,x在執行上下文中已經被清理掉了,但還是能夠憑借引用找到它,這就是閉包應用的簡單的解釋。
通過這樣的寫法,寫函數變得更加靈活了。add2實際接受到是一個匿名參數,這個參數保留著第一次傳入的參數。但你所需要的所有參數都傳完(是的,可以有不止一個參數,但需要通過curry函數的幫助),再執行操作,也就是上述代碼中x+y操作。
這樣無論你想add10,還是add20,都很輕松了。
問題來了
這樣寫函數太挫了,而且太麻煩了,有沒有什么好辦法呢?答案是有,那就是今天的重頭戲curry函數(通過curry函數處理一個函數的過程也叫柯里化)
先上代碼:
//柯里函數實質:傳遞給函數一部分參數來調用它,讓它返回一個函數來處理剩余參數 function curry(fx) { //要進行柯里化的函數的形參數量 var arity=fx.length return function f1() { //第一次傳入的參數數量 var args=[].slice.call(arguments,0) //若傳入的參數數量大于等于形參數量,代表現在萬事俱備(參數齊全了),可以直接執行函數了,直接將參數全部傳入fx函數中,并執行它 if (args.length>=arity) { return fx.apply(null,args) }else{ var f2=function() { //如果只傳入了一部分參數 var args2 = [].slice.call(arguments, 0) //判斷是否所有參數都傳完了,如果沒有,不斷concat新傳的參數,然后執行f1函數 return f1.apply(null, args.concat(args2)) } return f2 } } }
其實看書看到這部分的時候作者直接用lodash庫中的curry,看的十分蛋疼,覺得沒有詳細的代碼總歸不能理解的透徹。結果點開github上的作業(這本書有習題,就在GitHub上),發現有curry函數的實現。看了一圈有些小的不太理解的地方修改了一下,成了現在看到的函數。
現在就可以用curry了,用起來也是十分舒服(偷懶直接上書上代碼):
var match = curry(function(what, str) { return str.match(what); }); var replace = curry(function(what, replacement, str) { return str.replace(what, replacement); }); var filter = curry(function(f, ary) { return ary.filter(f); }); var map = curry(function(f, ary) { return ary.map(f); }); match(/s+/g, "hello world"); // [ " " ] match(/s+/g)("hello world"); // [ " " ] var hasSpaces = match(/s+/g); // function(x) { return x.match(/s+/g) } hasSpaces("hello world"); // [ " " ] hasSpaces("spaceless"); // null filter(hasSpaces, ["tori_spelling", "tori amos"]); // ["tori amos"] var findSpaces = filter(hasSpaces); // function(xs) { return xs.filter(function(x) { return x.match( /s+/g) }) } findSpaces(["tori_spelling", "tori amos"]); // ["tori amos"]
這樣是不是就能感受到curry的強大之處呢。在以后的函數式編程中還會不斷的遇見它的。
(寫在最后,關于curry函數實現的一點小問題,使用ES6的箭頭函數更貼切函數式編程的思想,但是箭頭函數無法識別arguments對象,所以還是老老實實寫匿名函數把)
(本文屬于讀書筆記,看的書是js函數式編程,在gitbook上就能看到)
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/89960.html
摘要:函數式編程,一看這個詞,簡直就是學院派的典范。所以這期周刊,我們就重點引入的函數式編程,淺入淺出,一窺函數式編程的思想,可能讓你對編程語言的理解更加融會貫通一些。但從根本上來說,函數式編程就是關于如使用通用的可復用函數進行組合編程。 showImg(https://segmentfault.com/img/bVGQuc); 函數式編程(Functional Programming),一...
摘要:而函數式編程中,則認為數據只是行為加工的產品。我們會發現,在函數式編程中,我們去除掉了主語。下面就來說說函數式編程的一些具體的東西。純函數在函數式編程中,有一個很重要的概念是純函數。 JavaScript是一門很神奇的語言,作為一門現代化的語言,他有很多很有特色的東西,這些東西,讓我們看到了一個十分自由化的未來,你永遠都不知道,自己是不是掌握了這門奇葩的要命的語言。本文,可能沒有那么多...
摘要:但是,對函數式編程而言,這個行為的重要性是毋庸置疑的。關于該模式更正式的說法是偏函數嚴格來講是一個減少函數參數個數的過程這里的參數個數指的是希望傳入的形參的數量。 原文地址:Functional-Light-JS 原文作者:Kyle Simpson-《You-Dont-Know-JS》作者 關于譯者:這是一個流淌著滬江血液的純粹工程:認真,是 HTML 最堅實的梁柱;分享,是...
摘要:譯者團隊排名不分先后阿希冬青蘿卜萌萌輕量級函數式編程第章融會貫通現在你已經掌握了所有需要掌握的關于輕量級函數式編程的內容。回頭想想我們用到的函數式編程原則。這兩個函數組合成一個映射函數通過,這就是融合見第章。 原文地址:Functional-Light-JS 原文作者:Kyle Simpson-《You-Dont-Know-JS》作者 關于譯者:這是一個流淌著滬江血液的純粹工程:...
閱讀 3146·2021-11-08 13:18
閱讀 2287·2019-08-30 15:55
閱讀 3609·2019-08-30 15:44
閱讀 3072·2019-08-30 13:07
閱讀 2784·2019-08-29 17:20
閱讀 1951·2019-08-29 13:03
閱讀 3413·2019-08-26 10:32
閱讀 3229·2019-08-26 10:15