### 什么是函數柯里化
在一個函數中首先填充幾個參數(然后再返回一個新函數)的技術稱為柯里化(Currying)。柯里化通常也稱部分求值,其含義是給函數分步傳遞參數,每次傳遞參數后部分應用參數,并返回一個更具體的函數接受剩下的參數,這中間可嵌套多層這樣的接受部分參數函數,直至返回最后結果。
#### 問題
要實現一個這樣的加法函數,使得:
```
add(1,2,3)(1)(2)(3)(4,5,6)(7,8)() === 42
```
首先,可以看到,這個函數,只有當參數為空的時候,才執行之前所有數值的加法,這樣的嵌套可以無限進行,當有參數的時候,add(1,2,3),這個時候的返回值應該是一個函數,這個函數存儲了1,2,3但是沒有執行加法(執行了也行,此處假設就不執行,只是起到保存參數的作用),這樣,繼續執行add(1,2,3)(2)()就能輸出1+2+3+2=8。
要實現這樣的一個函數,首先,返回值在參數不為空的時候必定返回一個函數,該函數還保存了之前的參數,這就需要用到閉包。
```
// add 函數柯里化
function add(){
//建立args,利用閉包特性,不斷保存arguments
var args = [].slice.call(arguments);
var _add = function(){
if(arguments.length === 0){
//參數為空,對args執行加法
return args.reduce(function(a,b){return a+b});
}else {
//否則,保存參數到args,返回一個函數
[].push.apply(args,arguments);
return _add;
}
}
//返回_add函數
return _add;
}
```
#### 通用的函數來對普通函數進行柯里化
```
// 通用的函數柯里化構造方法
function curry(func){
//新建args保存參數,注意,第一個參數應該是要柯里化的函數,所以args里面去掉第一個
var args = [].slice.call(arguments,1);
//新建_func函數作為返回值
var _func = function(){
//參數長度為0,執行func函數,完成該函數的功能
if(arguments.length === 0){
return func.apply(this,args);
}else {
//否則,存儲參數到閉包中,返回本函數
[].push.apply(args,arguments);
return _func;
}
}
return _func;
}
function add(){
return [].reduce.call(arguments,function(a,b){return a+b});
}
console.log(curry(add,1,2,3)(1)(2)(3,4,5,5)(5,6,6,7,8,8)(1)(1)(1)());//69
```
#### 題外話
實現數組扁平化:`var arr = [1,[2],[3,[4,5]],[6,[7,[8,9]]]]`
* arr.toString() -> "1,2,3,4,5,6,7,8,9"
* arr.flat(Infinity).toString() -> [1,2,3,4,5,6,7,8,9].toString() -> "1,2,3,4,5,6,7,8,9",其中,參數代表遍歷的深度,如果是1的話,則是[1,2,3,[4,5],6,[7,[8,9]]],如果是2的話,則是[1,2,3,4,5,6,7,[8,9]]