摘要:而柯里化是一個屬于函數式編程的一個常見的技巧。簡單來說,函數柯里化就是對高階函數的降階處理。讓你意外的是,這就是柯里化的基本思想,簡單地讓人猝不及防。
函數式編程是一種被部分JavaScript程序員推崇的編程風格,更別說 Haskell 和 Scala 這種以函數式為教義的語言。原因是因為其能用較短的代碼實現功能,如果掌握得當,能達到代碼文檔化(代碼本身具有很高可讀性甚至可以代替文檔)的效果,當然,泛濫使用也會使代碼可讀性變差。
而柯里化(Currying)是一個屬于函數式編程的一個常見的技巧。簡單來說,函數柯里化就是對高階函數的降階處理。
我們看下面這個函數:
function loc (a,b,c){ console.log(a+"-"+b+"-"+c); } loc("浙江","杭州","西湖區");//>>>浙江-杭州-西湖區
這是一個接收三個地名字符串的函數,功能是將三個地名字符串拼接到一起成為一個詳細的地址。
我們試試只傳入兩個參數:
loc("浙江","杭州");//>>>浙江-杭州-undefined
毫無疑義地,這個函數還是會正常執行,只是原本屬于“區”的位置由于沒有接收到參數而成了undefined。
其實這種情況很多,比如我們還要生成浙江-杭州-余杭區,浙江-杭州-拱墅區這樣的地名,但是我們沒必要每次都重新把浙江-杭州重新拼接一遍,所以你是不是會想,能不能只通過一個函數,把已經拼接過的字符串緩存起來,只去拼接新的字符串呢?我們或許可以把之前的函數改一下:
function loc (a) { return function(b){ return function(c){ console.log(a+"-"+b+"-"+c); } } }
好奇怪!這個loc函數只接收一個參數,而返回一個新的函數,這個函數也只接受一個參數,里面同樣返回一個函數,最后一個函數才返回三個參數拼接的字符串。
看起來是一個嵌套關系,好吧,讓我們看看它是否能實現剛剛的想法:
var Zhejiang = loc("浙江"); var Hangzhou = Zhejiang("杭州"); var Xihu = Hangzhou("西湖區"); //浙江-杭州-西湖區 var Yuhang = Hangzhou("余杭區"); //浙江-杭州-余杭區 var Lucheng = Zhejiang("溫州")("鹿城區"); //浙江-溫州-鹿城區
看,通過這樣的形式,我們輕松實現定制化函數啦!loc("杭州")不會急著把地名都拼接好,而是把杭州先存到閉包中,在需要拼接的時候才用到它。
讓你意外的是,這就是柯里化的基本思想,簡單地讓人猝不及防。
不,這不是你想要的結果,至少你已經考慮到一種恐怖的情況:如果參數有許多——比如100個,是不是要寫一個嵌套一百次的函數?
好在,我們可以寫一個通用函數來優雅地創建柯里化函數:
function curry(fn) { var outerArgs = Array.prototype.slice.call(arguments, 1); return function() { var innerArgs = Array.prototype.slice.call(arguments), finalArgs = outerArgs.concat(innerArgs); return fn.apply(null, finalArgs); }; }
有了這個基本函數之后,我們可以柯里化其他普通函數:
//一個普通函數 function loc(a,b,c){ console.log(a+"-"+b+"-"+c); } var workIn = curry(loc,"浙江","杭州","余杭區"); workIn();// >>> 浙江-杭州-余杭區
當然也可以這樣定制:
var zj = curry(loc,"浙江"); var city = curry(zj,"杭州"); city("余杭區"); //>>> 浙江-杭州-余杭區 city("上城區"); //>>> 浙江-杭州-上城區 zj("溫州","鹿城區");//>>> 浙江-溫州-鹿城區
簡直優雅。
以下我們來簡單分析以下這個通用函數:
function curry(fn) { var outerArgs = Array.prototype.slice.call(arguments, 1); return function() { var innerArgs = Array.prototype.slice.call(arguments), finalArgs = outerArgs.concat(innerArgs); return fn.apply(null, finalArgs); }; }
我們看這個curry函數,顯示接受一個參數,那就是需要被柯里化的函數。同時,因為JS神奇的函數傳參,我們可以在curry繼續放更多的參數,這些參數在函數體內部將以參數列表的形式存在,你可以通過arguments引用這個參數列表。注意,arguments引用的是一個參數列表而不是數組(雖然很像),所以數組的很多方法它都沒有。當然,這個難不倒我們,還記得我上一篇文章里提到的apply()黑科技嗎?傳送門:《快速理解JavaScript中apply()和call()的用法和用途》
outerArgs就是獲取除了第一個參數之外的參數列表。
而在返回的函數里,innerArgs獲取的是調用這個返回函數時傳入的所有參數,比如之前city("上城區")里面的"上城區"。
而finalArgs則是拼接這兩個數組(注意此時兩個參數列表都已經是正宗的數組,所以才可以使用concat方法)。
最后,使用apply,把所有參數組成的列表傳入到原來的函數,其實質就是在調用原始的函數,因為此時的參數都已齊全。
結尾福利:
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/78887.html
摘要:函數式編程,一看這個詞,簡直就是學院派的典范。所以這期周刊,我們就重點引入的函數式編程,淺入淺出,一窺函數式編程的思想,可能讓你對編程語言的理解更加融會貫通一些。但從根本上來說,函數式編程就是關于如使用通用的可復用函數進行組合編程。 showImg(https://segmentfault.com/img/bVGQuc); 函數式編程(Functional Programming),一...
摘要:以案例中的漏洞為例,安騎士的修復建議功能通過漏洞真實影響分析,能快速計算出漏洞真實受到影響較大的機器,在非常短的時間內給出企業修復排序的有效建議。 摘要: 關注網絡安全的企業大都很熟悉這樣的場景:幾乎每天都會通過安全媒體和網絡安全廠商接收到非常多的漏洞信息,并且會被建議盡快修復。盡管越來越多的企業對網絡安全的投入逐年增加,但第一時間修復所有漏洞,仍然是一件非常有挑戰的事。 關注網絡安全...
摘要:原文鏈接和都支持函數的柯里化函數的柯里化還與的函數編程有很大的聯系如果你感興趣的話可以在這些方面多下功夫了解相信收獲一定很多看本篇文章需要知道的一些知識點函數部分的閉包高階函數不完全函數文章后面有對這些知識的簡單解釋大家可以看看什么是柯里化 原文鏈接 Haskell和scala都支持函數的柯里化,JavaScript函數的柯里化還與JavaScript的函數編程有很大的聯系,如果你感興...
摘要:作為函數式編程語言,帶來了很多語言上的有趣特性,比如柯里化和反柯里化。在一些函數式編程語言中,會定義一個特殊的占位變量。個人理解不知道對不對延遲執行柯里化的另一個應用場景是延遲執行。不斷的柯里化,累積傳入的參數,最后執行。作為函數式編程語言,JS帶來了很多語言上的有趣特性,比如柯里化和反柯里化。 這里可以對照另外一篇介紹 JS 反柯里化 的文章一起看~ 1. 簡介 柯里化(Currying)...
摘要:作為函數式編程語言,帶來了很多語言上的有趣特性,比如柯里化和反柯里化。而反柯里化,從字面講,意義和用法跟函數柯里化相比正好相反,擴大適用范圍,創建一個應用范圍更廣的函數。作為函數式編程語言,JS帶來了很多語言上的有趣特性,比如柯里化和反柯里化。 可以對照另外一篇介紹 JS 柯里化 的文章一起看~ 1. 簡介 柯里化,是固定部分參數,返回一個接受剩余參數的函數,也稱為部分計算函數,目的是為了縮...
閱讀 3080·2021-11-24 10:47
閱讀 3831·2021-11-02 14:43
閱讀 2228·2021-09-26 10:15
閱讀 2253·2021-09-08 09:35
閱讀 560·2019-08-30 12:45
閱讀 2781·2019-08-29 17:04
閱讀 3214·2019-08-26 14:05
閱讀 1259·2019-08-26 12:10