虽然本系列是吐槽,但并不是为了黑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 = 0
let 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 = 2
let 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) // red
console.log(colors) // [ 'green', 'black' ]

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

总结

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

吐槽Javascript系列三:数组的陷阱相关推荐

  1. 怪异的JavaScript系列(三)

    译者按: JavaScript有很多坑,经常一不小心就要写bug. 原文: What the f*ck JavaScript? 译者: Fundebug 为了保证可读性,本文采用意译而非直译.另外,本 ...

  2. 【JavaScript系列】JS基础语法_从变量到数组一网打尽_有教程有实战

    [JavaScript系列]基础语法_从变量到数组一网打尽_有教程有实战 JavaScript基础语法目录 基础语法 延迟和异步脚本 变量 数据类型 数据类型简介 简单数据类型与复杂数据类型 栈和堆 ...

  3. javascript系列之DOM(三)---事件

    javascript系列之DOM(三)---事件 原文:javascript系列之DOM(三)---事件 事件是javascript跳动的心脏,是DOM所有成分结合的万金油.当我们在WEB 上进行某些 ...

  4. javascript基础系列:数组常用方法解析

    javascript基础系列:数组常用方法解析 今天是比较特殊的日子,我们编程人员共同的节日,1024,祝每个编程人员节日快乐! 数组是javascript必不可少的一项,今天让我们来总结一下数组操作 ...

  5. JavaScript中遍历数组的for for-in和forEach三种方式

    JavaScript中遍历数组的for for-in和forEach三种方式 for循环 let arr = [1,2,3,4,5,6];for(let i = 0; i < arr.lengt ...

  6. JavaScript初探 三 (学习js数组)

    JavaScript初探 (三) JavaScript数组 定义 创建数组 var 数组名 = [元素0,元素1,元素2,--] ; var arr = ["Huawei",&qu ...

  7. Javascript第三章创建数组的两种方式第一课

    跟java的区别 ,js中数值没有长度限制,大小可以自动调节, 而java 中的数组是线性的,放同样的类型,而且容量是定制,有限制 跟JAVA的区别 直接在控制台输入对象名,直接能把数组中的数全部查出 ...

  8. 深入理解JavaScript系列(1):编写高质量JavaScript代码的基本要点

    才华横溢的Stoyan Stefanov,在他写的由O'Reilly初版的新书<JavaScript Patterns>(JavaScript模式)中,我想要是为我们的读者贡献其摘要,那会 ...

  9. 深入理解JavaScript系列(32):设计模式之观察者模式

    介绍 观察者模式又叫发布订阅模式(Publish/Subscribe),它定义了一种一对多的关系,让多个观察者对象同时监听某一个主题对象,这个主题对象的状态发生变化时就会通知所有的观察者对象,使得它们 ...

最新文章

  1. 远程备份SQL Server 2005数据库
  2. InMobi收购美国Sprint旗下数据和广告公司Pinsight Media
  3. go 从入门到精通(二)基本数据类型和操作符
  4. SqlSession的使用范围---Mybatis学习笔记(五)
  5. IntelliJ IDEA 2018.2 发布,支持 Java 11
  6. 盘点中兴通讯强悍的战斗力
  7. AVFoundation 之数字媒体(音频)
  8. Magicodes.Admin.Core开源框架总体介绍
  9. Python安装geopandas库
  10. Atitit 效率提升分析与解决方案 1. 三大模式 优化资源配置 通过降低难度 提升培训 1 1.1. 优化资源配置 1 1.2. 通过降低难度 1 1.3. 提升培训 1 2. 有效与立即可
  11. 放弃 Google 搜索引擎,Firefox 欲用必应替代?
  12. 软件自动化测试的学习路线
  13. express文件上传中间件Multer详解
  14. xp计算机找不到音量调节,电脑音量图标消失无法调整声音大小的解决方案
  15. DFS入门级(模板)
  16. keyshot渲染图文教程_KeyShot中渲染汽车教程
  17. shp文件纯前端的上传、解析、编辑、下载
  18. 启发式搜索(Informed Search)-贪婪算法GBS+A*算法
  19. C语言自定义数组函数
  20. linux V4L2子系统——v4l2架构(3)之video_device

热门文章

  1. vue多个根节点上的属性继承
  2. ES5和ES6类的知识
  3. input file设置默认值_innodb_data_file_path设置--通过错误日志中page大小计算实际值...
  4. 华为智慧屏鸿蒙系统怎么样,鸿蒙系统初体验,华为智慧屏V65到底值不值得入手?...
  5. mysql删除注册表mysqld要删除吗_原神官方删除魈的观测枢数据,又要拆分机制吗?策划应该不傻吧?...
  6. trackbar控件显示刻度值_安卓自定义电平流图形控件
  7. python中的def函数括号里的默认值_Python中的默认参数值
  8. Androidstudio设置Ctrl+W关闭当前编辑的页面窗口
  9. 收藏:如何获取当前已经打开的IE对象(VB6代码)
  10. [vb]FindWindow使用方法