博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
吐槽Javascript系列三:数组的陷阱
阅读量:7143 次
发布时间:2019-06-28

本文共 2560 字,大约阅读时间需要 8 分钟。

虽然本系列是吐槽,但并不是为了黑Javascript,而是揭露它的一些特性(怪癖),只有更好的了解它,才能更好的使用它。本篇主要介绍数组中常见的隐患点。

龟速的map

在数组中,map是一个功能很强大的方法,先来见识一下:

let arr = [5, 2, 0]  .map(v => {    return v * 2  })  .filter(v => {    return v > 5  })console.log(arr) // [ 10 ]

它能返回一个新的数组,然后进行链式调用。别以为链式调用只有ES6中的Promise才有,es5的数组中早有了!

但据我观察,有些程序员会把它当成forEach来误用,如下:

let nums = [1, 3, 5, 7]nums.map(v => {  console.log(v)})

我问:你为什么要这样用呢?数组遍历应该用forEach和for循环来进行遍历,map主要是用来做映射生成新数组。

他答:map也可以遍历啊,完全没有问题,并且map比forEach还少敲几个字母,不是更方便吗?
我答:正常来说,的确可以这样用,但遇到大长度数组,涉及到性能的情况,要用forEach或for,因为他们之间的性能有很大区别,我们来看一个例子

// map 1770ms左右let sum = 0let arr = []for (let i = 0; i < 10 * 1000 * 1000; i++) {  arr.push(i)}console.time('p')arr.map(v => {  sum += v})console.timeEnd('p')

上面的例子中,如果用map来循环,在我的电脑上大约要2s的时间,而用forEach,470ms左右,用for,则只需要18ms左右。对于前端而言还好,但如果是在Node中(服务端)呢,那可是致命的。

一句话吐槽,map很慢如龟速!

删除的陷阱

数组也是一个对象,可以用delete运算符来从数组中移除元素,如下:

let arr = [1, 3, 5, 7, 9]delete arr[2]console.log(arr)

但是这种方式,会导致数组中将留下一个空洞,对于上面的例子来说,数组中的第三项5被删除,数组长度依旧是5,其他所有项的索引不变。

有点占着茅坑不拉shi的感觉,常常不是我们想要的结果。所以删除常用splice方法来做,我们来看一个例子:

// 根据索引curId,删除list中的项let curId = 2let list = [  {id: 1, name: 'a'},  {id: 2, name: 'b'},  {id: 3, name: 'c'},  {id: 4, name: 'd'}]list.forEach((v, index) => {  if (v.id === curId) {    list.splice(index, 1)  }})

上面代码将删除id为2的对象,删除后,数组将只有3个元素。看上去没有什么问题。但如果数组list中有二个一样的项(且相邻)呢?如下:

let list = [  {id: 1, name: 'a'},  {id: 2, name: 'b'},  {id: 2, name: 'b2'},  {id: 3, name: 'c'},  {id: 4, name: 'd'}]

你会发现,name为b2的项却删除不掉,这是为什么呢?因为forEach遍历删除第一项后,此时index为2,而这时数组也实时改变了,这时的数组的第三项为{id: 3, name: 'c'},而{id: 2, name: 'b2'}则被跳过了,没有遍历到!

这种情况,要用for循环来做,如下:

for (let i = 0; i < list.length; i++) {  if (list[i].id === curId) {    list.splice(i, 1)    i--  }}

当删除一项,得将索引减1,这样才能正确遍历每一项。

总结一句话,删除看情况,请小心索引!

sort的误用

小明是一个新手前端,他写了一个如下的升序排序:

const arr = [ 0, 1, 5, 10, 15, 10, 100, 99, 100 ]arr.sort((v1, v2) => {  return v1 > v2})console.log(arr)

跑一跑,完全没有问题,看似很正确!但数据再多一点,如下:

const arr = [ 0, 1, 5, 10, 15, 10, -2, -2, 100, 99, 100 ]

就会发现结果已经不对了,排序不能这样写!正确的写法应该是这样:

arr.sort((v1, v2) => {  return v1 > v2 ? 1 : -1})

上面二种写法看上去很像,但本质却很不一样,并且第一种写法在某些情况下返回的结果还是正确的,这正是隐患所在!

总结一句话:数组排序,比较函数中请返回1/-1而不是true/false!

unshift 命名之伤

每次看到这个方法,都会让我想起了install和uninstall,STOP!

它还有一个兄弟叫shift,它们两兄弟一个用于往数组头部添加项,一个用于往数组头部删除项。请看例子:

let colors = new Array()colors.unshift('black')console.log(colors) // [ 'black' ]colors.unshift('red', 'green')console.log(colors) // [ 'red', 'green', 'black' ]let item = colors.shift()console.log(item) // redconsole.log(colors) // [ 'green', 'black' ]

一句话吐槽,命名太奇怪!

总结

虽然,上面提到的一些陷阱和槽点值得注意,但平心而论,js中的数组是非常灵活的,其提供的很多方法用起来也很方便。

转载地址:http://zamrl.baihongyu.com/

你可能感兴趣的文章
win7 X64 进程名称不一致,导致杀进程失效!
查看>>
简单的传输文件范例
查看>>
LINQ查询索引
查看>>
ABP(现代ASP.NET样板开发框架)系列之13、ABP领域层——数据过滤器(Data filters)...
查看>>
Nginx 详细安装部署教程
查看>>
删除字符,用外部函数
查看>>
BZOJ4755: [JSOI2016]扭动的回文串——题解
查看>>
Kubernetes
查看>>
【总结整理】用户的需求分析:问对问题才能找准用户需求----摘自《人人都是产品经理》...
查看>>
javascript 去掉小数末尾多余的零
查看>>
Ext Js简单Data Store创建及使用
查看>>
Outlook Web App简介
查看>>
使用java处理大文件
查看>>
按钮式超链接
查看>>
HTML常用标签与CSS基础知识
查看>>
双行表头DatagridView的简单实现
查看>>
Java图形界面开发—列出指定目录
查看>>
关于 58 996 浪潮 奋进者计划 华为 奋斗者协议—— 小论!
查看>>
纯CSS实现蜂窝六边形的个性相册
查看>>
HTML--CSS
查看>>