您的位置:首页 > Web前端 > JavaScript

es6--javascript数组降维,从es5分析到es6,(详解reduce方法)欢迎补充

2017-12-26 15:54 1436 查看
数组降维,很多都是二维数组转一维数组,但随着大数据时代的来临,很多都是多为数组,多为数组如何降维,下面将一一分析

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位置

所以,网上给的有些解释,并不恰当
4000
和语义化

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数组降维中,遇到的问题,都解释了,理解浅显,记下来,让自己温故而知新
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息