標籤:
函數柯裡化currying,是函數式編程非常重要的一個標誌。它的實現需要滿足以下條件,首先就是函數可以作為參數進行傳遞,然後就是函數可以作為傳回值return出去。我們依靠這個特性編寫很多優雅酷炫的代碼。那我們來看一下最簡單的實現。
大家一般都是舉addSum的例子,我當然也不例外。
add = (num1)-> return (num2)-> return num1 + num2; add3 = add(3);add5 = add(5);add3(5) # 返回8add5(5) # 返回10
上述例子其實已經對柯裡化的實現,有一個非常好的瞭解了。其實也就是“分步求值”,我們可以把第一個參數通過閉包儲存起來,以供return出去的匿名函數使用。所以我們可以根據add來自訂各種各樣的新函數。
我們要使某個函數可以柯裡化,難道一定要在函數建立時,就具有柯裡化的特性嗎?假設我們的add函數,起初並不具有柯裡化特性的,我們需要怎麼做才能讓它柯裡化呢?
add = (num1, num2)-> return num1 + num2;curry = (fn)-> args = [].slice.call(arguments, 1); return ()-> [].push.apply(args, arguments); return fn.apply(this, args);add5 = curry(add, 5)add5(3) # 返回8
原理還是一樣的,我們通過curry函數,讓fn需要的第一次的參數通過閉包儲存在args的變數裡,以供匿名函數使用。最後結合第二次需要的參數,使用apply一次性匯入args,完成操作。
上述我們看到的都是分兩步求值,這其實並不符合我們更豐富的實際需求。我們需要考慮如何才可以將函數柯裡化變成我們需要的想分步便分步,想停止便停止呢?
首先我們需要約定一個規則,這個規則和大部分的Getter/Setter方法一樣。當函數沒有參數時,執行的是Getter,而有參數的話,則是執行“Setter”。(這個也是Javascript實現簡陋的函數重載的一種方法)
curry = (fn)-> args = []; return ()-> if arguments.length == 0 return fn.apply(this, args); else [].push.apply(args, arguments); return arguments.callee; addSum = ()-> sum = 0; for num in arguments sum += num; return sum;currySum = curry(addSum);currySum(1, 2, 3);currySum(1);currySum(1);currySum(1);currySum(1);currySum(); # 返回 10
更多的柯裡化帶來的妙處,則需要你在實際使用中,細細品味。相信一旦你掌握了這個靈活可靠的方法,可以為你帶來不一樣的感受。實現原理其實也很簡單,通過閉包,將每次的參數儲存在args數組了。當不傳參執行Getter時,就直接通過apply函數,將數組參數匯入。我們只需要在addSum函數那裡處理好匯入的參數數組即可。
轉載至:http://yikaj.gitcafe.io/2015/04/06/Javascript%E5%87%BD%E6%95%B0%E6%9F%AF%E9%87%8C%E5%8C%96/
Javascript函數柯裡化