題目一:函數(shù)式編程當(dāng)中有個非常重要的概念就是 函數(shù)柯里化,一個接受 任意多個參數(shù) 的函數(shù),如果執(zhí)行的時候傳入的參數(shù)不足,那么它會返回新的函數(shù),新的函數(shù)會接受剩余的參數(shù),直到所有參數(shù)都傳入才執(zhí)行操作。這種技術(shù)就叫柯里化,請你完成 curry 函數(shù),它可以把任意的函數(shù)進(jìn)行柯里化,效果如下:
const f = (a, b, c d) => { ... }
const curried = curry(f)
curried(a, b, c, d)
curried(a, b, c)(d)
curried(a)(b, c, d)
curried(a, b)(c, d)
curried(a)(b, c)(d)
curried(a)(b)(c, d)
curried(a, b)(c)(d)
// 這些函數(shù)執(zhí)行結(jié)果都一樣
例如:
const add = curry((a, b ,c ,d) => a + b + c +d)
add (1,2,3,4)=10
add(1)(2,3)(4)=10
add(1,2,3)(4)=10
add(1)(2)(3)(4)=10
題目二:不定參數(shù)處理
實(shí)現(xiàn)一個add方法,使計(jì)算結(jié)果能夠滿足如下預(yù)期:
add(1)(2)(3) = 6;
add(1, 2, 3)(4) = 10;
add(1)(2)(3)(4)(5) = 15;
答案
首先函數(shù)柯里化因?yàn)閰?shù)固定,使用vars數(shù)組保存每次傳進(jìn)來的參數(shù),然后判斷fn的參數(shù)個數(shù),如果fn參數(shù)個數(shù)正好等于vars數(shù)組中保存的個數(shù),那么執(zhí)行fn,否則遞歸一次,返回curried函數(shù),繼續(xù)等待輸入。這里外層curry 函數(shù)只會執(zhí)行一次便會被剝離,之后add會變成curried的一個引用,同時curried可以閉包引用外層的vars,使得每次傳入的參數(shù)可以長久保存。
我的答案一:函數(shù)柯里化
const curry = (fn,vars=[]) =>{
const curried=(...args)=>{
for(let i of [...args]){
vars.push(i)
}
if(vars.length==fn.length){
return fn(...vars)
}else{
return curry(fn,vars)
}
}
return curried
}
網(wǎng)上更為優(yōu)秀的答案:用延展符將push做了簡化
const curry = (f, args1 = []) => (...args2) => {
const args = [ ...args1, ...args2 ]
return f.length === args.length
? f(...args)
: curry(f, args)
}
參考上面網(wǎng)上優(yōu)秀答案的思路,寫出這個不定參數(shù)處理add函數(shù),...args可以接受不定參數(shù),由于題目二中并沒有題目一中const add = curry((a, b ,c ,d) => a + b + c +d)函數(shù)劫持的過程,所以不能直接返回函數(shù)定義,而是要返回一個執(zhí)行完的函數(shù)curried(...args),同時在curried中再返回一個函數(shù)定義curried,這樣就可以把函數(shù)連接起來了。由于參數(shù)不定,這里對每次傳入的參數(shù)都要進(jìn)行執(zhí)行處理,執(zhí)行方法是利用函數(shù)的隱式轉(zhuǎn)換,當(dāng)函數(shù)執(zhí)行結(jié)束時會有一個toString的操作,來使函數(shù)能參與其他的運(yùn)算,這里我們將toString從新定義,返回vars中的累加值,從而實(shí)現(xiàn)add運(yùn)算。
我的答案二:不定參數(shù)處理
const add=(...args)=>{
let vars=[]
const curried=(...c)=>{
vars=[...vars,...c]
return curried
}
curried.toString=()=>{
return vars.reduce((a,b)=>a+b,0)
}
return curried(...args)
}