函數柯里化currying,是函數式編程很是重要的一個標誌。它的實現須要知足如下條件,首先就是函數能夠做爲參數進行傳遞,而後就是函數能夠做爲返回值return出去。咱們依靠這個特性編寫不少優雅酷炫的代碼。那咱們來看一下最簡單的實現。編程
你們通常都是舉addSum的例子,我固然也不例外。數組
add = (num1)-> return (num2)-> return num1 + num2; add3 = add(3); add5 = add(5); add3(5) # 返回8 add5(5) # 返回10
上述例子其實已經對柯里化的實現,有一個很是好的瞭解了。其實也就是「分步求值」,咱們能夠把第一個參數經過閉包保存起來,以供return出去的匿名函數使用。因此咱們能夠根據add來自定義各類各樣的新函數。閉包
咱們要使某個函數能夠柯里化,難道必定要在函數建立時,就具備柯里化的特性麼?假設咱們的add函數,起初並不具備柯里化特性的,咱們須要怎麼作才能讓它柯里化呢?app
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實現簡陋的函數重載的一種方法)this
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函數那裏處理好導入的參數數組便可。code
更多的柯里化帶來的妙處,則須要你在實際使用中,細細品味。相信一旦你掌握了這個靈活可靠的方法,能夠爲你帶來不同的感覺。ip