`Array(100).map(() => 1)` 为什么全为空?

🧑‍💻 写在开头
点赞 + 收藏 === 学会🤣🤣🤣

问题场景

群里有位同学在刷 LeetCode,想初始化一个长度为 100 的全 1 数组:

bash 复制代码
const arr = Array(100).map(() => 1)
console.log(arr.length)    // 100
console.log(arr[0])        // undefined ❓
console.log(arr.every(v => v === 1))  // false ❓

100 个元素一个都没映射成功。 更诡异的是,arr.length 确实是 100,但 for...of 遍历却循环了 0 次。这是 JavaScript 最具迷惑性的坑之一。

原因分析

关键概念:稀疏数组(Sparse Array)

Array(100) 创建的是一个稀疏数组------它只有 length 属性被设置为 100,内部没有任何实际元素,即"空槽位"(empty slots)。

打开浏览器控制台验证:

bash 复制代码
const a = Array(3)
console.log(a)           // [empty × 3]
console.log(0 in a)      // false --- 索引 0 根本就不存在!
console.log(Object.keys(a))  // [] --- 没有 key

map、forEach、filter、reduce、every、some 等所有迭代方法都会跳过空槽位,这就是映射不起作用的根本原因。

对比一下:

bash 复制代码
// 真实元素 vs 空槽位
const real = [undefined, undefined, undefined]
console.log(0 in real)        // true --- 索引存在
real.map(x => 1)              // [1, 1, 1]

const sparse = Array(3)
console.log(0 in sparse)      // false --- 索引不存在
sparse.map(x => 1)            // [empty × 3]

解决方案

生成填充数组的最佳实践:

方案一:Array.from(推荐 ✅)

bash 复制代码
const arr = Array.from({ length: 100 }, () => 1)
// 或简写
const arr = Array.from({ length: 100 }, () => 1)

Array.from 会主动遍历 length 并在每个索引上调用回调,不会跳过。

方案二:.fill().map() 组合

bash 复制代码
const arr = Array(100).fill().map((_, i) => i)
// 先生成密集数组再 map

.fill() 会用实际值填充所有空槽,之后再 map 就不会跳过了。

方案三:扩展运算符(ES6+)

bash 复制代码
const arr = [...Array(100)].map(() => 1)

展开运算符会遍历迭代器,而 Array(100) 的迭代器会生成 undefined 填充空槽,结果变成一个密集数组。

方案四:Array.apply 黑科技

bash 复制代码
const arr = Array.apply(null, Array(100)).map(() => 1)

原理相同------apply 会将稀疏数组展平为密集数组。

实用场景:生产中常踩的雷

场景 1:假分页渲染

bash 复制代码
// ❌ 踩坑写法
const skeleton = Array(loading ? 10 : 0).map(() => <Skeleton />)
// 不会渲染任何骨架屏!

// ✅ 正确写法
const skeleton = Array.from({ length: loading ? 10 : 0 }, () => <Skeleton />)

场景 2:稀疏 JSON 反序列化

bash 复制代码
const json = '[1, , 3]'  // JSON 中的空元素
const arr = JSON.parse(json)
console.log(arr)          // [1, empty, 3]
arr.map(x => x * 2)      // [2, empty, 6] --- 你丢了一个元素!

场景 3:删除元素不缩容

bash 复制代码
const arr = [1, 2, 3, 4, 5]
delete arr[2]             // 慎用!这会制造空槽!
console.log(arr.map(x => x))  // [1, 2, empty, 4, 5]

始终用 splice 代替 delete 删除数组元素。

要点总结

一句话记忆法:

Array(n) 造的是"鬼屋"------有门牌号但里面没人住;迭代方法只会给"活人"敲门。

实战中,初始化数组始终用 Array.from({ length }) 或 ...Array(n),别被 Array(n).map() 坑了面试分。

如果对您有所帮助,欢迎您点个关注,我会定时更新技术文档,大家一起讨论学习,一起进步。

相关推荐
IT_陈寒8 小时前
Java中equals方法比了个寂寞?原来这才是正确的重写姿势
前端·人工智能·后端
默_笙8 小时前
🚓 分诊台与拆题术:让 RAG 学会判断和规划
前端·javascript
CopyCode8 小时前
用 AI 迁项目有多爽?我把 Webpack 迁 Vite 的全过程记下来了
前端·架构
去伪存真8 小时前
Electron 自动化发布指南:GitHub Actions 跨平台打包全纪录
前端·electron
计算机魔术师8 小时前
OpenAI智能体失控闯进美国政府网站,53张用户图片外泄背后
前端
颜进强8 小时前
14 · NestJS ExecutionContext 执行上下文:守卫、拦截器、过滤器拿到的"同一个 context",为什么能力不一样?
前端·后端·ai编程
程序员Flycan9 小时前
🚀 跨域终结者:前端代理服务器(Proxy)原理解析与配置总结
前端
怕浪猫9 小时前
顶级模型一句话,AI 写出了能玩的 QQ飞车
前端·面试·github
huakoh9 小时前
MCP 报错分不清?先看响应里是 result 还是 error
前端
呃呃呃呃ex9 小时前
10. 现代前端工程化:ES6 React 项目实战与原理解析
前端·javascript