JS数组里的隐秘陷阱:稀疏数组的坑

起因

今天在写代码时,遇到了map方法无法遍历的情况。代码如下:

js 复制代码
//想生成一个元素为1~n的数组
let eles = new Array(9)
eles = eles.map((item,idx)=>idx+1)

结果 eles 数组并没有如期望的 [1,2...9] ,而仍是 [empty,empty,...] , 随后我就使用 eles.map((item,idx)=>console.log(idx)) 来查看 map 中的回调是否调用, 结果是没有调用。

描述

遇到这个奇怪的问题, 我查看了 MDN 中 map 的描述, 发现其中有这么一段:

callback is invoked only for indexes of the array which have assigned values (including undefined).

callback 函数只会在有值的索引上被调用,具体不被调用的情况如下:

  • 没有设置索引
  • 索引被删除
  • 索引上未设值 MDN 上对符合以上条件的数组称为 稀疏数组

稀疏数组的定义

在算法领域,稀疏数组(Sparse Array)是一种优化数据结构,用于存储那些大部分元素为默认值(通常是0或undefined)的数组。这种数据结构通过只存储非默认值的元素来节省内存空间,同时提供一个索引映射来快速访问这些非默认值的元素。稀疏数组在处理大量稀疏数据时非常高效,因为它避免了为未使用的元素分配空间。

然而,在JavaScript中,稀疏数组的描述有些差异,可以查看MDN中的描述。我总结了以下几个要点:

  1. 在JS中,稀疏数组指的是那些包含"空槽"(holes)的数组。
  2. 这些空槽是数组中的索引位置,它们没有被赋予任何值,甚至不是undefined。空槽的存在使得数组在视觉上看起来像是有连续的未赋值的元素,但实际上这些位置并不包含任何值。
  3. JavaScript的稀疏数组在某些操作中会表现出与undefined值相似的行为,但在数组方法如mapeveryfilter等的调用中,空槽并不会被视为有效元素,因此这些方法不会在空槽的索引上执行回调函数。

实际结果

按照以上的说明,我进行了以下的用例测试。

  1. 使用 new Array 创建空数组, 结果 callback 未调用。
js 复制代码
let eles = new Array(9)
eles.map((item=>console.log(item))
  1. 使用 [,,,] 创建空数组, 结果 callback 未调用。
js 复制代码
let eles = [,,,]
eles.map((item=>console.log(item))
  1. 使用 [undefined,undefined,undefined] 创建数组, 结果 callback 调用。
js 复制代码
let eles = [undefined,undefined,undefined]
eles.map((item=>console.log(item))
  1. 使用 [,undefined,undefined] 创建数组, 结果不为 empty 的元素被调用 callback。
js 复制代码
let eles = [,undefined,undefined]
eles.map((item=>console.log(item))
//undefined *2
  1. 使用 delete 删除元素, 被删除索引的值变为 empty, 该索引不会调用 callback。
js 复制代码
let eles = [1,2,3]
delete eles[0]
eles.map((item=>console.log(item))
//2,3

结论

如同上面描述所说 map 方法对于稀疏数组中元素为 empty 的"空槽"不会调用 callback。

与 map 表现一致的的数组方法还有: every , filter, flat, flatMap, forEach, reduce, reduceRight, some

会对所有元素调用的数组方法有: find, findIndex

对于有需要初始化数组元素可以使用 fill 方法, 或者使用 Array.apply(null,Array(9)) 的方式。

相关推荐
hedley(●'◡'●)11 分钟前
基于cesium和vue的大疆司空模仿程序
前端·javascript·vue.js·python·typescript·无人机
百思可瑞教育13 分钟前
构建自己的Vue UI组件库:从设计到发布
前端·javascript·vue.js·ui·百思可瑞教育·北京百思教育
CappuccinoRose39 分钟前
JavaScript 学习文档(二)
前端·javascript·学习·数据类型·运算符·箭头函数·变量声明
全栈前端老曹1 小时前
【MongoDB】深入研究副本集与高可用性——Replica Set 架构、故障转移、读写分离
前端·javascript·数据库·mongodb·架构·nosql·副本集
NCDS程序员1 小时前
v-model: /v-model/ :(v-bind)三者核心区别
前端·javascript·vue.js
小杨同学呀呀呀呀2 小时前
Ant Design Vue <a-timeline>时间轴组件失效解决方案
前端·javascript·vue.js·typescript·anti-design-vue
qq_532453532 小时前
使用 Three.js 构建沉浸式全景图AR
开发语言·javascript·ar
Mr Xu_10 小时前
告别冗长 switch-case:Vue 项目中基于映射表的优雅路由数据匹配方案
前端·javascript·vue.js
前端摸鱼匠11 小时前
Vue 3 的toRefs保持响应性:讲解toRefs在解构响应式对象时的作用
前端·javascript·vue.js·前端框架·ecmascript
sleeppingfrog11 小时前
zebra通过zpl语言实现中文打印(二)
javascript