for循环遍历所有索引位置,包括空位;forEach、for...of、map等跳过空位但处理显式undefined;in操作符和hasOwnProperty可检测空位存在性。

JavaScript 中 undefined 在数组遍历时的特殊表现,核心在于它既可能真实存在(显式或隐式赋值),也可能根本不存在(空位 / sparse slot)——而不同遍历方式对这两种“undefined”完全不加区分,却行为迥异。
for 循环:忠实按 length 遍历所有索引位置
for (let i = 0; i 只看数组的 <code>length 属性,从 0 到 length - 1 逐个访问每个索引。无论该索引是否被实际赋值,都会读取其当前值:
- 若索引有值(如
arr[0] = "a"),输出该值; - 若索引从未被赋值(如稀疏数组
[1,,3]中的arr[1]),返回undefined; - 若索引被显式设为
undefined(如arr[2] = undefined),也返回undefined。
它无法区分“空位”和“显式 undefined”,但保证顺序、全覆盖、不漏索引。
for...in 循环:只枚举可枚举的自有属性名
for...in 遍历的是对象的**可枚举自有属性键名**。由于数组本质是对象,它的数字索引就是属性名,但:
立即学习“Java免费学习笔记(深入)”;
- 它跳过所有未定义的索引(即稀疏数组中的空位),只输出已设置的索引(如
[1,,3]中只输出"0"和"2"); - 它可能意外列出数组上添加的其他可枚举属性(如
arr.custom = "x"); - 它不保证顺序(尽管多数引擎对数字索引保持插入顺序,但规范不保证);
- 它不会遍历继承属性或不可枚举属性(如
length或toString方法)。
所以它看到的不是“元素”,而是“哪些索引被真正写入过”。
Array.prototype 方法(如 map、forEach):与 for 行为一致,但跳过空位
ES5+ 的迭代方法(forEach、map、filter 等)在设计上**刻意忽略稀疏数组中的空位**:
- 对于
[1,,3],forEach只执行两次回调(索引 0 和 2),索引 1 完全不触发; - 它们仍会处理显式设为
undefined的项(如[1, undefined, 3]会触发三次); - 这是规范明确规定的:空位(empty slot)不参与迭代,而
undefined值是合法的迭代项。
这种设计让逻辑更贴近“有效元素”的语义,避免无意义的 undefined 处理。
如何判断一个位置是空位还是 undefined 值?
仅靠 arr[i] === undefined 无法区分二者。可靠方式是使用 in 操作符或 hasOwnProperty:
-
i in arr→true表示该索引是显式存在的属性(哪怕值是undefined);false表示纯空位; -
arr.hasOwnProperty(i)效果相同,且更明确(排除原型链属性); - 例如:
const a = [1,,3]; a[1] === undefined为true,但1 in a为false。
这个区别直接影响你选择哪种遍历方式,以及是否需要做额外的空位检测。


















