数组降维,很多都是二维数组转一维数组,但随着大数据时代的来临,很多都是多为数组,多为数组如何降维,下面将一一分析

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数组降维中,遇到的问题,都解释了,理解浅显,记下来,让自己温故而知新