map() 产生的“空洞”在 JSON 序列化时变为 null,而非跳过或报错;空洞指稀疏数组中完全缺失的索引位置,map 不调用回调,结果数组对应位置仍为空槽,JSON.stringify 统一将其转为 null。

map() 产生的“空洞”(empty slots)在 JSON 序列化时会变成 null,而不是被跳过或报错——这是关键表现,也是容易踩坑的地方。
什么是 map 产生的“空洞”
当原数组是稀疏数组(sparse array),即某些索引位置根本没有定义(不是 undefined,而是完全缺失),map() 不会为这些位置调用回调函数,结果数组中对应位置仍为空槽:
const arr = [1, , 3]; // 索引 1 是空槽(不是 undefined) const mapped = arr.map(x => x * 2); // [2, <1 empty slot>, 6]
注意:mapped[1] 在语言层面既不是 undefined,也不可枚举,1 in mapped 返回 false,console.log(mapped) 可能显示 [2, empty, 6]。
空洞在 JSON.stringify() 中如何表现
JSON.stringify() 对空槽的处理是明确且统一的:所有空槽都被序列化为 null。
const sparse = [1, , 3]; const mapped = sparse.map(x => x); console.log(JSON.stringify(mapped)); // "[1,null,3]"
这和 undefined、null、0、"" 等值的序列化行为不同:
-
undefined在数组中会被转成null(仅限数组;对象中则直接忽略) -
null保持为null - 空槽也变成
null—— 和undefined在最终 JSON 字符串里效果一致,但来源完全不同
✅ 关键区别:空槽是“不存在”,
undefined是“存在但未赋值”。但在 JSON 层面,二者都落地为null。
常见误判场景
- 你以为后端收到的是
[1, null, 3]就代表前端传了null,其实可能是map遇到稀疏数组自动填充的; - 你用
Array.from({ length: 3 })创建数组再map,得到的是全空槽数组,JSON.stringify后是[null,null,null],容易误以为是三个null元素; - 使用
new Array(3).map(...)也会产生同样效果,因为new Array(3)创建的就是含 3 个空槽的稀疏数组。
JSON.stringify(new Array(3).map(() => 'x')); // "[null,null,null]" // 不是 ["x","x","x"] —— 因为 map 根本没执行回调!
如何避免混淆
- 需要确定性长度时,优先用
Array(n).fill()而非new Array(n); - 处理可能稀疏的输入前,先用
Array.isArray(arr) && arr.length === arr.filter(() => true).length检查是否稠密(不推荐线上用,仅调试); - 更稳妥:用扩展运算符转为稠密数组(会把空槽转成
undefined),再map:
const safe = [...sparse].map(x => x ?? 'default');
- 如果必须保留结构,且需区分空槽与
null,JSON 不是合适载体 —— 改用自定义序列化(如带元数据的格式)或改用Array.from({ length }, (_, i) => ...)显式构造。
不复杂但容易忽略


















