资讯专栏INFORMATION COLUMN

吐槽Javascript系列三:数组的陷阱

U2FsdGVkX1x / 562人阅读

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

虽然本系列是吐槽,但并不是为了黑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中的数组是非常灵活的,其提供的很多方法用起来也很方便。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/102000.html

相关文章

  • 吐槽Javascript系列一:slice()、substr()和 substring()

    摘要:点评我们来看这样一个例子给定一个字符串,要求去掉最后一个逗号。大胆假想一下,如果把踢出去,就保留和,你还会懵吗或者更大胆一点,把和都踢出去,就只保留,我反正感觉整个世界都清静了系列链接吐槽系列一和吐槽系列二数组中的和方法吐槽系列三数组的陷阱 实不相瞒,对于字符串中的slice()、substr()和 substring()这三个方法,我自己很长一段时间都是理不清的,每次用都得查一下文档...

    waltr 评论0 收藏0
  • 吐槽Javascript系列二:数组splice和slice方法

    摘要:原来,它的替换功能实际上是通过删除和添加来完成的。在只有一个参数的情况下,方法返回从该参数指定位置开始到当前数组末尾的所有项。它并不改变原数组。吐槽我曾经一直困惑数组中的删除方法,当知道删除这项伟大的任务竟然交给了,我心里是失望的。 战斗英雄你当,漂亮媳妇儿你娶,怎么啥好事都被你给占了——《激情燃烧的岁月》 谈起这两个方法,新手不蒙,我是不信!正如吐槽Javascript系列一:sli...

    lookSomeone 评论0 收藏0
  • CSS技巧

    摘要:技巧使你的更加专业这是上关于技巧的一篇译文,另外你也可以在本项目看到原文。列举了一些很实用的技巧,比如给空内容的标签添加内容,逗号分隔列表等等。排序算法看源码,把它背下来吧排序算法的封装。主要帮助初学者更好的掌握排序算法的实现。 成为专业程序员路上用到的各种优秀资料、神器及框架 成为一名专业程序员的道路上,需要坚持练习、学习与积累,技术方面既要有一定的广度,更要有自己的深度。 Java...

    DangoSky 评论0 收藏0
  • CSS技巧

    摘要:技巧使你的更加专业这是上关于技巧的一篇译文,另外你也可以在本项目看到原文。列举了一些很实用的技巧,比如给空内容的标签添加内容,逗号分隔列表等等。排序算法看源码,把它背下来吧排序算法的封装。主要帮助初学者更好的掌握排序算法的实现。 成为专业程序员路上用到的各种优秀资料、神器及框架 成为一名专业程序员的道路上,需要坚持练习、学习与积累,技术方面既要有一定的广度,更要有自己的深度。 Java...

    zgbgx 评论0 收藏0
  • 【ES6】改变 JS 内置行为代理与反射

    摘要:通过对这些底层内置对象的代理陷阱和反射函数,让开发者能进一步接近引擎的能力。显然,与要求代理目标对象必须是一个函数,这两个代理陷阱在函数的执行方式上开启了很多的可能性,结合使用就可以完全控制任意的代理目标函数的行为。 代理(Proxy)可以拦截并改变 JS 引擎的底层操作,如数据读取、属性定义、函数构造等一系列操作。ES6 通过对这些底层内置对象的代理陷阱和反射函数,让开发者能进一步接...

    lushan 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<