- undefined 是一个真实存在的值,数组里真的存了一个元素,只是值是 undefined。
- 空槽(empty slot)根本没有元素,索引不存在,就像那个格子不存在。
区别
1.创建方式不同
const a = [1, undefined, 3];
const b = [1, , 3]; // 注意这里的逗号 ,, 产生了空槽
- a[1] 的值是 undefined(数组里真的有一个元素)
- b[1] 是一个“空槽”,数组索引 1 处根本没有元素
2."in" 运算符区别
1 in a // true,因为有元素,只是值是 undefined
1 in b // false,因为它是空槽,不存在元素
3.数组长度长度一样,但内容不同
a.length // 3
b.length // 3
长度一样,但内部结构不一样。
4.forEach / map / filter 之类对空槽会跳过
a.forEach((v,i)=>console.log(i, v));
// 输出:0 1, 1 undefined, 2 3
b.forEach((v,i)=>console.log(i, v));
// 输出:0 1, 2 3 (索引1被跳过)
5.JSON.stringify 的区别
JSON.stringify([1, undefined, 3])
// "[1,null,3]" undefined 转成 null
JSON.stringify([1, , 3])
// "[1,null,3]" 空槽也转成 null
注意:虽然结果一样,但内部意义不同。
6.map 的行为更明显
[1, undefined, 3].map(x => 100)
// [100, 100, 100]
[1, , 3].map(x => 100)
// [100, , 100] // 注意空槽保留为空槽!
空槽不会被 map 处理,也不会变为 undefined,而是继续保持空槽。
7.数组序列化展开时的区别
[...a] // [1, undefined, 3]
[...b] // [1, undefined, 3] <-- 空槽在展开时会变成 undefined
创建空槽的行为
-
Array 构造函数(单个数字参数)
const a = Array(3); // [empty x 3] -
数组字面量中使用省略的逗号
const a = [1, , 3]; // 中间是空槽 -
使用 delete 删除数组元素
const a = [1,2,3]; delete a[1]; // [1, empty, 3] -
使用稀疏数组赋值跳过索引
const a = []; a[2] = 'x'; // [empty x 2, "x"] -
使用 map/filter/slice 等操作保留空槽
[ , 1, , 2].map(x => x) // 仍然是 [empty, 1, empty, 2] -
使用 holes 的数组做扩展、解构(会变 undefined,但原数组仍然有空槽)
const a = [ , 2, 3]; const b = [...a]; // b 里不是空槽,是 undefined // a 自身仍然有空槽
创建 undefined 元素的行为
-
普通赋值
const a = []; a[0] = undefined; // 明确设置 -
使用扩展运算符展开空槽数组
const a = [ , 1]; const b = [...a]; // b = [undefined, 1] -
使用解构赋值展开空槽
const [a, b] = [, 1]; // a === undefined -
JSON.parse 解析含 null 的 json(与 undefined 不同,但不会产生空槽)
JSON.parse("[1, null, 3]") // [1, null, 3](这里不会产生空槽,而是“null”,我放在这里是为了对比。)
-
map/filter 等回调返回 undefined
[1,2,3].map(x => undefined); // [undefined, undefined, undefined] -
函数返回 undefined 导致数组填充 undefined
const a = Array.from([1,,3], x => x); // => [1, undefined, 3] -
直接写 undefined 作为数组元素
[undefined, 2, undefined]
Top comments (0)