1. 程式人生 > >es6--javascript陣列降維,從es5分析到es6,(詳解reduce方法)歡迎補充

es6--javascript陣列降維,從es5分析到es6,(詳解reduce方法)歡迎補充

陣列降維,很多都是二維陣列轉一維陣列,但隨著大資料時代的來臨,很多都是多為陣列,多為陣列如何降維,下面將一一分析

1.二位陣列降維

var arr=[1,2,[3,4,5]]
Array.prototype.concat.apply([],arr)//[1,2,3,4,5]

這裡利用的是apply,方法,自動打散引數,再concat拼接,
但這種方法,只能解決一層降維,雖然apply傳遞的引數,是陣列形式,但只能打破一層陣列,如果是3維或3維以上,將不能降維到一維

var arr=[1,2,[3,[4,5]]]
Array.prototype.concat.apply([],arr)//[1,2,3,4,5]`
//[1,2,3,[4,5]]

2.為解決上述問題,遞迴

var recursion=function(arr){
    var len=arr.length,newarr=[];
    for(var i=0;i<len;i++){      
        if(Array.isArray(arr[i]))
            newarr.push.apply(newarr,recursion(arr[i]))
        else newarr.push(arr[i])
    }
    return newarr
}

還可用foreach或者棧方法解決,點選進入


3.利用reduce,優雅解決
隨著es6,7,新增的陣列api,上述方法顯得過於繁瑣,需要一個有逼格的程式碼

let flatten = arr => arr.reduce((begin,current)=>{
        Array.isArray(current)?
        begin.push(...flatten(current)):
        begin.push(current);
        return begin
    },[])

(1)function a( x){return x}
箭頭函式,只有一個引數時,可省略小括號,大括號裡只有一句return時,可以省略return和大括號,let a = x=>x
(2)reduce 陣列api,網上可以搜到很多,但有的解釋總是說的模糊不清,我把我的理解寫在這裡,供參考

arr.reduce(),函式總共有兩個引數

arr.reduce(callback[, initialValue])

第一個引數callback還有四個引數,第二個為設定的初始值(可有可無),後面再說
callback函式有四個引數:
prev: 上一次疊加的結果值或者初始值
cur: 當前會參與疊加的項
index: 當前值的索引
arr: 陣列本身
個人認為,上面寫的四個引數,是現在很多網上的解釋,我認為這種解釋,造成了很多誤區,

var  arr = [1, 2, 3, 4];
sum = arr.reduce(function(prev, next, index, arr) {
    console.log(prev, next, index);
    return prev+ next;
})
console.log(arr, sum);

這是網上關於reduce很常見的例子,累加求和,可以很輕鬆的打印出,callback裡四個引數,觀察結果,
關於上面的例子,我來列出迴圈每次打印出什麼

//第1次迴圈
console.log(prev, next, index);//1  2  1
//第2次迴圈
console.log(prev, next, index);//3  3  2
//第3次迴圈
console.log(prev, next, index);//6  4  3

解釋此次程式碼第一次迴圈輸出的值,下面迴圈輸出依次對應此解釋
對應的是,
prev : 1 上一個值
next : 2 陣列中第二個位置即arr[1]的值2 (陣列從0位置開始),
index : 當前陣列中值得位置,是1位置

到這裡,肯定會有人奇怪,reduce不是累加函式,為什麼不是從陣列0位置開始,這就跟reduce第二個引數initialValue有關了,

initialValue,給reduce設定的初始執行的值,先解釋到這

var  arr = [1, 2, 3, 4];
sum = arr.reduce(function(prev, next, index, arr) {
    console.log(prev, next, index);
    return prev+ next;
},0)
console.log(arr, sum);

再執行,看輸出

//第1次迴圈
console.log(prev, next, index);//0  1  0
//第2次迴圈
console.log(prev, next, index);//1  2  1
//第3次迴圈
console.log(prev, next, index);//3  3  2
//第4次迴圈
console.log(prev, next, index);//6  4  3

解釋此次程式碼第一次迴圈輸出的值,下面迴圈輸出依次為此
對應的是,
prev : 0 上一個值,其實是設定的初始值
next : 1 陣列中第1個位置即arr[0]的值1 (陣列從0位置開始),
index : 當前陣列中值得位置,是0位置
所以,網上給的有些解釋,並不恰當和語義化
arr.reduce(callback(begin,current,index,arr)[, initialValue])更合適一些
begin : 初始值,若reduce函式,沒有設定初始值,預設陣列的第1項,為起始值
current : 當前值,reduce函式,所執行,當前對應的值
index : 當前所執行值在陣列中的位置
arr : 當前被執行的陣列
這樣理解會更方便一些,不用像有的解釋,老寫成callback(prev,next,index,arr),第一個引數,是上一個值,第二個引數是下一個值,容易誤導初學者(本人也是初學者,也被誤導了),

let flatten = arr => arr.reduce((begin,current)=>{
        Array.isArray(current)?
        begin.push(...flatten(current)):
        begin.push(current);
        return begin
    },[])

再來看這個程式碼,就容易理解多了,
設定了初始值,是一個空陣列,那麼執行時候,會從arr[0]位置開始,
接下來就容易了,判斷每一項是否是陣列,如果不是,遞迴,如果是,直接push,但遞迴的時候,發下一個問題begin.push(…flatten(current))是什麼
這是es6函式中的rest引數,更語義化的arguments物件
原先,js函式中,如果沒有寫明確的引數,比如

var a=function(){
    console.log(Array.isArray(arguments))//false
    var sum=0,len=arguments.length
    for(var i=0;i<len;sum+=arguments[i++]);
    return sum
}
a(1,2,3,4)//10

arguments是一個類陣列物件
但是,es6函式新增rest引數,把過去arguments類陣列物件,直接變成了陣列物件形式的引數

var a=(...num)=>{
    console.log(Array.isArray(num))//true
    var sum=0,len=num.length
    for(var i=0;i<len;sum+=num[i++]);
    return sum
}
a(1,2,3,4)//10

回到上面降維的函式

let flatten = arr => arr.reduce((begin,current)=>{
    Array.isArray(current)?
    begin.push(...flatten(current)):
    begin.push(current);
    return begin
},[])

發現,begin.push(…flatten(current))
可以理解的是遞迴呼叫自己,那這個函式本身,最後執行結果,return begin 是返回一個數組
那arr.push([1,2,3])

var arr=[]
arr.push([1,2,3])//[[1,2,3]]

這尼瑪,不是陣列降維麼,怎麼還是多為陣列
關鍵在 “…” ,這是一個操作符,
“…”叫做展開操作符
允許一個表示式在某處展開,用於
存在多個引數(函式呼叫)、多個元素(陣列)、多個變數(解構賦值)
不清楚的,請去看阮一峰老師的es6教程或者網上一搜一堆的解構賦值案例
會把陣列,自動展開成單個值

var arr=[];
arr.push(...[1,2,3])//[1,2,3]

綜上,reduce陣列降維中,遇到的問題,都解釋了,理解淺顯,記下來,讓自己溫故而知新