前言
首先什么是数组展开?
假如现在有这样一个需求: 将后台的一个多重 List 数据, 展开成一个 List 后, 并去重后排序;
["a", "b", ["c", "d"], [["d"],"e"], "f"] => ["a", "b", "c", "d", "e"];
数组去重我们前面在《JS 专题之数组去重》已经讲过了, 那么前一步的多重数组展开成单层数组, 该如何处理呢?
这就来到我们所要探讨的数组展开了.
根据需求的特点, 数组展开需要进行迭代和递归.
回答文章开头的问题:
将多重数组转化成单层数组的过程就是数组展开, 也叫作数组扁平化 (flatten)
一, 循环加递归
最简单的思路: 循环中判断, 如果子元素是数组则递归.
- function flatten(origin) {
- var result = [];
- for(var i = 0; i<origin.length; i++) {
- var item = origin[i];
- if(Array.isArray(item)) {
- result = result.concat(flatten(item))
- } else {
- result.push(item);
- }
- }
- return result;
- }
- var arr = ["a", "b", ["c", "d"], [["d"],"e"], "f"];
- flatten(arr); // ["a", "b", "c", "d", "d", "e", "f"]
二, toString()
数组的原型对象上有一个方法, toString, 它能把数组的所以元素转化成用逗号隔开的字符串.
- var arr = [1, [2, 3, [4]], "a", "b", ["c", "d"], [["d"],"e"], "f"];
- arr.toString() // "1,2,3,4,a,b,c,d,d,e,f"
- // 所以, 利用 split 先把字符串转化为单层数组, 再进行处理.
- const flatten = (origin) => origin.toString().split(','); // ["1", "2", "3", "4", "a", "b", "c", "d", "d", "e", "f"]
由于 toString 转化为字符串的时候, 不会区分字符串和数字类型, 在进行区分数据类型的时候要注意.
三, split
上面的方法, 我们用 toString() 将数组转化为字符串, 那么我们也可以用 split 来做:
- var arr = [1, [2, 3, [4]], "a", "b", ["c", "d"], [["d"],"e"], "f"];
- function flatten(arr) {
- return arr.join(',').split(',');
- }
- console.log(flatten(arr)). // ["1", "2", "3", "4", "a", "b", "c", "d", "d", "e", "f"]
同样, 这种字符串和数组互转的过程, 不适合多种数据类型同时处理.
四, reduce
我们注意到其实数组扁平化其实就是 "迭代 + 拼接 (累加) + 递归" 的过程, 数组 reduce 方法既可以迭代又可以累加, 适合做数组扁平化.
- function flatten(origin){
- return origin.reduce(function(init, item){
- return init.concat(Array.isArray(item) ? flatten(item) : item)
- }, [])
- }
- var arr = [1, [2, 3, [4]], "a", "b", ["c", "d"], [["d"],"e"], "f"];
- console.log(flatten(arr)) // [1, 2, 3, 4, "a", "b", "c", "d", "d", "e", "f"]
五, some + concat
some 会遍历数组的每一个元素, 判断是否有元素都满足条件, 最后返回布尔值. some 一旦返回真值后, 其后的元素就不会继续监测.
- function flatten(origin) {
- while (origin.some(item => Array.isArray(item))){
- origin = [].concat.apply([], origin);
- }
- return origin;
- }
- var arr = [1, [2, 3, [4]], "a", "b", ["c", "d"], [["d"],"e"], "f"];
- console.log(flatten(arr)) // [1, 2, 3, 4, "a", "b", "c", "d", "d", "e", "f"]
六, some + 扩展运算符
ES6 扩展运算符... 可以将两重数组转换为单层数组:
- [].concat(...[1, [2, 3, [4]], "a", "b", ["c", "d"], [["d"],"e"], "f"]); // [1, 2, 3, Array(1), "a", "b", "c", "d", Array(1), "e", "f"]
- // 利用 some 方法, 我们可以实现多重转换为单层:
- function flatten(origin) { while(origin.some(item=> Array.isArray(item))) {
- origin = [].concat(origin);
- } return origin;
- }
- var arr = [1, [2, 3, [4]], "a", "b", ["c", "d"], [["d"],"e"], "f"];
- console.log(flatten(arr)) // [1, 2, 3, 4, "a", "b", "c", "d", "d", "e", "f"]
总结
数组扁平化其实就是利用元素迭代 + 元素拼接 (叠加)+ 递归调用来对数组进行处理, 达到将多层数组转换为单层数组的过程. 欢迎关注我的个人公众号 "谢南波", 专注分享原创文章.
掘金专栏 JavaScript 系列文章
JavaScript 之变量及作用域
JavaScript 之声明提升
JavaScript 之执行上下文
JavaScript 之变量对象
JavaScript 之原型与原型链
JavaScript 之作用域链
JavaScript 之闭包
JavaScript 之 this
JavaScript 之 arguments
JavaScript 之按值传递
JavaScript 之例题中彻底理解 this
JavaScript 专题之模拟实现 call 和 apply
JavaScript 专题之模拟实现 bind
JavaScript 专题之模拟实现 new
JS 专题之事件模型
JS 专题之事件循环
JS 专题之去抖函数
JS 专题之节流函数
JS 专题之函数柯里化
JS 专题之数组去重
JS 专题之深浅拷贝
来源: https://juejin.im/post/5c5c2744f265da2dbe02bd66