← 返回题目列表

JavaScript 稀疏数组和数组空位是什么?遍历时有什么差异?

中等 第 23 / 29 题 更新于 2026/07/29
JavaScriptArray稀疏数组

简化版

稀疏数组是存在“空位”的数组。空位不是显式的 undefined,而是这个索引根本没有属性。

不同遍历方法对空位处理不同:mapforEach 会跳过空位,for...of 会把空位读成 undefinedObject.keys 只返回真实存在的索引。面试中要区分“值为 undefined”和“索引不存在”。

详细版

数组本质上也是对象,索引是特殊的属性名。下面两个数组看起来相似,但内部不同。

const a = [undefined];
const b = [];
b.length = 1;

console.log(0 in a); // true
console.log(0 in b); // false

a[0] 这个属性存在,值是 undefinedb[0] 这个属性不存在,只是 length 为 1。

遍历差异:

const arr = [1, , 3];

arr.forEach(x => console.log(x)); // 1, 3
console.log(arr.map(x => x * 2)); // [2, empty, 6]
console.log([...arr]); // [1, undefined, 3]
console.log(Object.keys(arr)); // ["0", "2"]

实际开发中,应避免制造稀疏数组。需要固定长度时可以用 Array.from({ length: n }, ...) 创建真实元素。

完整版教学

一、空位和 undefined 的区别

空位表示某个索引没有对应属性,undefined 表示属性存在但值是 undefined

const withUndefined = [undefined];
const withHole = new Array(1);

console.log(withUndefined[0]); // undefined
console.log(withHole[0]); // undefined
console.log(0 in withUndefined); // true
console.log(0 in withHole); // false

两者读取结果一样,但存在性不同。

面试里最关键的判断不是 arr[i] === undefined,而是 i in arrObject.hasOwn(arr, i)

二、稀疏数组怎么产生

常见来源有三类。

const a = [1, , 3];

const b = [];
b[3] = "x";

const c = new Array(5);

b 的长度是 4,但只有索引 3 存在。c 的长度是 5,但 0 到 4 都是空位。

数字例子:

表达式length实际存在的索引
[1, , 3]30、2
new Array(3)3
[undefined, undefined]20、1

三、不同遍历 API 的处理差异

forEachmapfiltersomeevery 通常跳过空位,因为它们只访问存在的元素。

const arr = [10, , 30];

arr.forEach((v, i) => console.log(i, v));
// 0 10
// 2 30

for...of 通过数组迭代器读取每个位置,空位会表现为 undefined

for (const item of arr) {
  console.log(item);
}
// 10
// undefined
// 30

四、map 会保留空位

map 跳过空位,但结果数组会保留对应空位。

const arr = [1, , 3];
const next = arr.map(x => x * 2);

console.log(next); // [2, empty, 6]
console.log(1 in next); // false

这会导致后续链式处理出现不直观结果。比如你以为数组长度为 3 就处理了 3 个元素,实际回调只执行了 2 次。

五、数组方法和对象属性视角

数组索引本质上是对象属性。

const arr = [1, , 3];

console.log(Object.keys(arr)); // ["0", "2"]
console.log(arr.length); // 3

length 表示最大索引加一,不表示真实元素数量。统计真实元素数量要看 keys 或显式过滤。

const realCount = Object.keys(arr).length; // 2

六、如何创建没有空位的数组

需要初始化固定长度数组时,更推荐 Array.from

const list = Array.from({ length: 3 }, (_, i) => i + 1);
console.log(list); // [1, 2, 3]

如果使用 new Array(3).map(...),回调不会执行。

console.log(new Array(3).map(() => 1)); // [empty × 3]

七、常见误区与追问

  • 误区:空位就是 undefined。 空位是索引不存在,undefined 是索引存在但值为 undefined
  • 误区:数组 length 等于真实元素个数。 length 主要受最大索引影响。
  • 误区:new Array(3).map 会执行三次。 空位会被 map 跳过。
  • 误区:所有遍历方式处理空位都一样。 forEachfor...of 的表现不同。
  • 追问:如何判断某个索引是否真实存在? 可以用 index in arrObject.hasOwn(arr, index)
  • 追问:业务里为什么要避免稀疏数组? 它会让遍历、序列化、统计和展示出现不一致。

八、加强记忆

把数组想成带 length 的对象:

[1, , 3]
  ├─ property "0" = 1
  ├─ property "1" missing
  ├─ property "2" = 3
  └─ length = 3

答题顺序可以是:先定义空位,再用 0 in arr 区分 undefined,接着讲遍历差异,最后强调初始化数组用 Array.from,减少稀疏数组带来的隐性问题。