js中閉包結(jié)合遞歸等于柯里化原理解析
引言
我們不妨以兩數(shù)相加為例子,遞進(jìn)說(shuō)明。
我們通常是這樣寫一個(gè)函數(shù)來(lái)求得 兩數(shù)相加 的值:
function sum(a,b){ console.log(a+b) } sum(1,2)
這樣寫一點(diǎn)毛病沒有!
不過呢?問題總會(huì)在發(fā)展中產(chǎn)生,產(chǎn)品經(jīng)理又要加一個(gè)值,需求:三數(shù)相加;
咱通常來(lái)說(shuō),第一時(shí)間,就在原基礎(chǔ)上,直接再加一個(gè)參數(shù)就是了;
于是,修改后像是這樣:
function sum(a,b,c){ console.log(a+b+c) } sum(1,2,3)
問:這樣寫,有毛病嗎??
答:太有毛病了!
這樣一改,既違反了:“開閉原則”、又違反了:“單一職責(zé)原則”。
為不太熟悉設(shè)計(jì)原則的小伙伴們,簡(jiǎn)單解釋下:
- 什么是“開閉原則”?即:我們編程中要盡可能的避免直接修改函數(shù)、類或模塊,而是要在原有基礎(chǔ)上拓展它;
- 什么是“單一職責(zé)原則”?即:每個(gè)函數(shù)、類或模塊,應(yīng)該只負(fù)責(zé)一個(gè)單一的功能;
首先,咱修改了 sum 函數(shù)的傳參以及內(nèi)部的調(diào)用 ⇒ 則違反“開閉原則”
其次,sum 函數(shù)本來(lái)只負(fù)責(zé)兩數(shù)相加,修改后,它又負(fù)責(zé)三數(shù)相加,職責(zé)已經(jīng)發(fā)生了變化 ⇒ 則違反 “單一職責(zé)原則”;
如果正規(guī)按照單一責(zé)任來(lái)寫,應(yīng)該是:
// 負(fù)責(zé)兩數(shù)相加 function sum2(a,b){ console.log(a+b) } // 負(fù)責(zé)三數(shù)相加 function sum3(a,b,c){ console.log(a+b+c) }
事實(shí)上,是不可能這樣去寫的,因?yàn)槿绻幸蝗f(wàn)個(gè)數(shù)相加,得寫一萬(wàn)個(gè)函數(shù)。
而 加法只有一個(gè)!! 不管你最終要加幾個(gè)值,總是要一個(gè)加一個(gè)。
于是乎,我們?cè)O(shè)想,能不能寫一個(gè)這樣的函數(shù):它的功能,就是“加”,參數(shù)跟幾個(gè),我就加幾個(gè)。
// 負(fù)責(zé)“加法”, function addCurry(){ ... ... ... } addCurry(1)(2) // 兩數(shù)相加 addCurry(1)(2)(3) // 三數(shù)相加 ... addCurry(1)(2)(3)...(n) // n 數(shù)相加
沒錯(cuò),這個(gè)函數(shù)就是:柯里化?。。ɑ蛘哒f(shuō)這個(gè)過程叫柯里化,這個(gè)思想叫柯里化,本瓜認(rèn)為這里不需要太死扣定義)
接著,我們一步步來(lái)試試,它會(huì)是怎樣構(gòu)成的?
為了能夠?qū)崿F(xiàn)一個(gè)加一個(gè),即存儲(chǔ)參數(shù)的目的,我們想一想,還有什么法寶?
沒錯(cuò),JS 奧義:閉包!
其實(shí),本瓜時(shí)常想,閉包的終極秘密是什么?最后將其理解為 4 個(gè)金光閃閃的大字:延遲處理!
什么意思?簡(jiǎn)單解釋下:
function directHandle(a,b){ console.log("直接處理",a,b) } directHandle(111,222) // 直接處理 111 222 function delayHandle(a){ return function(b){ console.log("延遲處理",a,b) } } delayHandle(111) // ? (b){ // console.log("延遲處理",a,b) // }
如上 delayHandle(111)
不像 directHandle(111,222)
直接打印值,而是先返回一個(gè)函數(shù) f(b)
;111 也被臨時(shí)保存了,delayHandle(111)(222)
,則得到相同的輸出。這就是:延遲處理的思想。
另外補(bǔ)一句:
延遲處理是函數(shù)式編程的精華所在,在不能保證每個(gè)函數(shù)都是純函數(shù)的前提下,在管道處理的最后,再進(jìn)行處理,能最大程度的保證減少副作用。也就是 Monad 思想,此處不做展開。
言歸正傳,于是乎,我們借用閉包來(lái)實(shí)現(xiàn)最初版的柯里化:
// 兩數(shù)相加 function addCurry(a){ return function(b){ console.log(a+b) } } addCurry(1)(2) // 三數(shù)相加 function addCurry(a){ return function(b){ return function(c){ console.log(a+b+c) } } } addCurry(1)(2)(3)
寫兩個(gè)閉包的過程,聰明的你一定就明白了,這樣一直寫下去,不就是遞歸嗎?!
于是乎,我們知道,當(dāng)參數(shù)是 n 個(gè)的時(shí)候,需要遞歸 n-1 次 return function
于是乎,addCurry 寫法如下:
let arr = [] function addCurry() { let arg = Array.prototype.slice.call(arguments); // 遞歸獲取后續(xù)參數(shù) arr = arr.concat(arg); if (arg.length === 0) { // 如果參數(shù)為空,則判斷遞歸結(jié)束 return arr.reduce((a,b)=>{return a+b}) // 求和 } else { return addCurry; } } addCurry(1)(2)(3)()
OK,至此,,大功告成??!
以上,用最簡(jiǎn)單的代碼解釋了 —— 為什么我說(shuō):柯里化 == 閉包+遞歸 ?
柯里化是一種思想,上面的 addCurry 可以說(shuō)是最簡(jiǎn)單的一種實(shí)踐。在函數(shù)式編程中,Curry 更是大放異彩,比如 compose(fn1)(fn2)(fn3)…(fnN)(args) 等等。
如果以后有人再問你柯里化,可以往這個(gè)方向上答。。。
以上就是閉包結(jié)合遞歸等于柯里化原理解析的詳細(xì)內(nèi)容,更多關(guān)于閉包結(jié)合遞歸等于柯里化的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
實(shí)現(xiàn)微信小程序的wxml文件和wxss文件在webstrom的支持
這篇文章主要介紹了實(shí)現(xiàn)微信小程序的wxml文件和wxss文件在webstrom的支持的相關(guān)資料,需要的朋友可以參考下2017-06-06javascript使用btoa和atob來(lái)進(jìn)行Base64轉(zhuǎn)碼和解碼
javascript原生的api本來(lái)就支持,Base64,但是由于之前的javascript局限性,導(dǎo)致Base64基本中看不中用。當(dāng)前html5標(biāo)準(zhǔn)正式化之際,Base64將有較大的轉(zhuǎn)型空間,對(duì)于Html5 Api中出現(xiàn)的如FileReader Api, 拖拽上傳,甚至是Canvas,Video截圖都可以實(shí)現(xiàn)2017-03-03js實(shí)現(xiàn)兔年轉(zhuǎn)圈圈動(dòng)畫示例
這篇文章主要為大家介紹了js實(shí)現(xiàn)兔年轉(zhuǎn)圈圈動(dòng)畫示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-01-01一文詳解typeScript的extends關(guān)鍵字
這篇文章主要為大家介紹了typeScript的extends關(guān)鍵字使用示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-03-03gulp-font-spider實(shí)現(xiàn)中文字體包壓縮實(shí)踐
這篇文章主要為大家介紹了gulp-font-spider實(shí)現(xiàn)中文字體包壓縮實(shí)踐詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-03-03JS前端可擴(kuò)展的低代碼UI框架Sunmao使用詳解
這篇文章主要為大家介紹了JS前端可擴(kuò)展的低代碼UI框架Sunmao使用詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-07-07微信小程序 倒計(jì)時(shí)組件實(shí)現(xiàn)代碼
這篇文章主要介紹了微信小程序 倒計(jì)時(shí)組件實(shí)現(xiàn)代碼的相關(guān)資料,需要的朋友可以參考下2016-10-10