虽然本系列是吐槽,但并非为了黑Javascript,而是揭露它的一些特性(怪癖),只有更好的了解它,才能更好的使用它。本篇主要介绍数组中常见的隐患点。
在数组中,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方法来作,咱们来看一个例子:es5
// 根据索引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中有二个同样的项(且相邻)呢?以下:code
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,这样才能正确遍历每一项。
总结一句话,删除看状况,请当心索引!排序
小明是一个新手前端,他写了一个以下的升序排序:索引
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!
每次看到这个方法,都会让我想起了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中的数组是很是灵活的,其提供的不少方法用起来也很方便。