1 背景
不知道老铁们有没有遇到过一道面试题:如何将一个多维数组展开成一个一维数组?当时我遇到的时候还不了解flat这个神奇的方法,用了最传统的解决方法进行解决。

const flatten = arr => arr.toString().split(’,’).map(item => +item);

const arr = [1, 2, [3, 4, [5, 6]]];
console.log(flatten(arr)); // [ 1, 2, 3, 4, 5, 6 ]
复制代码
上述方法是不是很神奇,会将多层级的数组展开成为一个层级,但是该方式其实存在很大问题的,下面让我们一起看看这些问题。

不管多少层级都会展开为一个层级;
处理后的结果其实都是字符串,需要后续再转换为原来的类型。
正是基于这个契机,发现了ES6新增了flat函数,这个函数天生就是为数据扁平化处理而生的。

2 flat基础
flat() 方法会按照一个可指定的深度递归遍历数组,并将所有元素与遍历到的子数组中的元素合并为一个新数组返回。

flat方法的用法如下所示:
const newArray = arr.flat([depth])
复制代码
小试牛刀
const arr = [1, 2, [3, 4, [5, 6]]];
console.log(arr.flat(1)); // [ 1, 2, 3, 4, [ 5, 6 ] ]
console.log(arr.flat(2)); // [ 1, 2, 3, 4, 5, 6 ]
复制代码
3 实现
flat这么香,那么我们是否可以自己实现一个呢?实现该方法的方式有很多,下面就让我们一起看看这五种方式。(注:这五种方式试MDN上给出的替代方案)

3.1 使用reduce和concat
该方式实现起来虽然很简单,但是存在一个很大的缺陷:只能展开一层,对于多层的情况将无能为力。其思想总结起来为以下两个步骤:

利用reduce函数去依次处理每个数组中的元素;
利用concat将当前的数组元素(值或子数组)添加到结果数组中。
// 使用reduce和concat
Array.prototype.flat1 = function () {
return this.reduce((acc, val) => acc.concat(val), []);
}
复制代码
3.2 使用reduce + concat + isArray + recursivity
该方式已经具备展开多层的能力了,其实现思想可总结为以下几点:

利用reduce函数去依次处理每个数组中的元素;
利用concat将当前元素添加到结果数组中;
利用isArray判断当前数组中的元素是不是一个数组;
利用递归思想展开多层级的数组。
// 使用reduce + concat + isArray +recursivity
Array.prototype.flat2 = function (deep = 1) {
const flatDeep = (arr, deep = 1) => {
return deep > 0 ? arr.reduce((acc, val) => acc.concat(Array.isArray(val) ? flatDeep(val, deep - 1) : val), []) : arr.slice();
}

return flatDeep(this, deep);

}
复制代码
3.3 使用forEach + concat + isArray +recursivity
该方式与上述方式很类似,能够设定层级展开,只是遍历数组由reduce转换为forEach。

// 使用forEach + concat + isArray +recursivity
// forEach 遍历数组会自动跳过空元素
Array.prototype.flat3 = function (deep = 1) {
const result = [];
(function flat(arr, deep) {
arr.forEach((item) => {
if (Array.isArray(item) && deep > 0) {
flat(item, deep - 1);
} else {
result.push(item);
}
})
})(this, deep);

return result;

}
复制代码
3.4 使用for of + concat + isArray +recursivity
该方式与上述方式很类似,能够设定层级展开,只是遍历数组利用了for of方法

// 使用for of + concat + isArray +recursivity
// for of 遍历数组会自动跳过空元素
Array.prototype.flat4 = function (deep = 1) {
const result = [];
(function flat(arr, deep) {
for(let item of arr) {
if (Array.isArray(item) && deep > 0) {
flat(item, deep - 1);
} else {
// 去除空元素,因为void 表达式返回的都是undefined,不适用undefined是因为undefined在局部变量会被重写
item !== void 0 && result.push(item);
}
}
})(this, deep);

return result;

}
复制代码
3.5 使用堆栈stack
该方式主要利用堆栈的思想,将一个多层数组全部展开为一层。其思想可总结为以下几个步骤:

将要处理的数组放到一个栈中处理;
从栈顶取出元素,判断该元素类型,若为数组,则将该数组展开再放回栈顶;若为普通元素则将其放到结果中;
循环遍历,至到栈为空。
// 使用堆栈stack
Array.prototype.flat5 = function() {
const stack = […this];
const result = [];
while (stack.length > 0) {
const next = stack.pop();
if (Array.isArray(next)) {
stack.push(…next);
} else {
result.push(next);
}
}

// 反转恢复原来顺序
return result.reverse();

}
复制代码
1.如果觉得这篇文章还不错,来个分享、点赞吧,让更多的人也看到

如果你觉得这篇文章对你有点用的话,麻烦请给我们的开源项目点点star: http://github.crmeb.net/u/defu 不胜感激 !
来自 “开源世界 ” ,链接: https://ym.baisou.ltd/post/737.html ,如需转载,请注明出处,否则将追究法律责任。 ​​​​​​

前端百题——竟然有五种方式实现flat方法相关推荐

  1. 前端百题斩【020】——竟然有五种方式实现flat方法

    写该系列文章的初衷是"让每位前端工程师掌握高频知识点,为工作助力".这是前端百题斩的第20斩,希望朋友们关注公众号"执鸢者",用知识武装自己的头脑. 20.1 ...

  2. 前端百题斩【024】——我从浏览器控制台看到了五种存储方式

    写该系列文章的初衷是"让每位前端工程师掌握高频知识点,为工作助力".这是前端百题斩的第24斩,希望朋友们关注公众号"执鸢者",用知识武装自己的头脑. 打开浏览器 ...

  3. 前端百题斩【029】——原来浏览器中存在五类进程

    写该系列文章的初衷是"让每位前端工程师掌握高频知识点,为工作助力".这是前端百题斩的第29斩,希望朋友们关注公众号"执鸢者",用知识武装自己的头脑. 浏览器已经 ...

  4. 前端百题斩【032】——两个角度一个实战了解事件循环

    写该系列文章的初衷是"让每位前端工程师掌握高频知识点,为工作助力".这是前端百题斩的第32斩,希望朋友们关注公众号"执鸢者",用知识武装自己的头脑. 111 9 ...

  5. 前端百题斩【028】——浏览器中的请求们

    写该系列文章的初衷是"让每位前端工程师掌握高频知识点,为工作助力".这是前端百题斩的第28斩,希望朋友们关注公众号"执鸢者",用知识武装自己的头脑. 通过浏览器 ...

  6. 前端百题斩【035】——一文了解HTTP缓存

    写该系列文章的初衷是"让每位前端工程师掌握高频知识点,为工作助力".这是前端百题斩的第35斩,希望朋友们关注公众号"执鸢者",用知识武装自己的头脑.提前透露一下 ...

  7. 前端百题斩【027】——解决跨域的常用利器CORS全解

    写该系列文章的初衷是"让每位前端工程师掌握高频知识点,为工作助力".这是前端百题斩的第27斩,希望朋友们关注公众号"执鸢者",用知识武装自己的头脑. 27.1 ...

  8. 前端百题斩【023】——赋值、浅拷贝、深拷贝大PK

    写该系列文章的初衷是"让每位前端工程师掌握高频知识点,为工作助力".这是前端百题斩的第23斩,希望朋友们关注公众号"执鸢者",用知识武装自己的头脑. 相信老铁们 ...

  9. 前端百题斩【021】——通俗易懂的防抖与节流

    写该系列文章的初衷是"让每位前端工程师掌握高频知识点,为工作助力".这是前端百题斩的第21斩,希望朋友们关注公众号"执鸢者",用知识武装自己的头脑. 性能一直是 ...

最新文章

  1. bash: dotnet: 未找到命令..._Docker 常用命令(.NET Core示例)
  2. ASP .NET Core Web Razor Pages系列教程二:添加模型到Razor Pages网络应用程序
  3. linux服务器上nginx日志访问量统计命令
  4. Django搭建个人博客(二)
  5. Netty之WebSocket和四种IO介绍
  6. 台式机计算机操作系统怎么看,电脑操作系统是32位还是64位的怎么查看
  7. druid 多数据源_Spring Boot + Mybatis 中 配置Druid多数据源并实现自由切换
  8. 通过Service访问应用 (2)
  9. leetcode 341. 扁平化嵌套列表迭代器(dfs)
  10. Java jar 版本 查看
  11. JavaScript的一些小技巧(转)
  12. 太损了!“特斯拉刹车失灵”同款白T恤已上架电商平台
  13. java接收json字符串_JAVA后台接收前台传过来的json字符串并解析获得key 和value
  14. windows 配置 Gitlab、Gitee(码云) 的git开发环境
  15. C/C++链接过程相关
  16. 用WPF做报表控件(一)
  17. vue项目IE浏览器中打不开,为空白页
  18. Frodo and pillows
  19. 上传图片转为base64码再以url形式传值
  20. h5 php捕鱼,完整的html5捕鱼游戏源码分享

热门文章

  1. 教你炒股票1:不会赢钱的经济人,只是废人!
  2. 广播和多播(组播)的区别
  3. 【Android笔记104】Android之壁纸管理器(WallpaperManager)的使用
  4. 像好几天没吃东西似的抢着吃
  5. Max如何渲染360全景图
  6. html5 x5引擎,HTML5+CSS3从入门到精通之快速了解X5内核浏览器,video兼容
  7. python的简单调试
  8. JQuery 数组的增删改
  9. 分享一款管理微信小程序的神器
  10. 通过查看端口状态查看mongodb是否已经启动