为何JavaScript的splice()在两种数组创建方式下表现不同?
核心原因:稀疏数组与密集数组的行为差异
你的猜测完全正确,两段代码的差异本质是**稀疏数组(sparse array)**和密集数组的区别导致的。
先明确两段代码的实际输出
- 第一段(
new Array(3))运行结果:undefined - 第二段(字面量创建)运行结果:
3
详细解析差异根源
1. 两种数组创建方式的本质区别
const arr = [1, 2, 3]:创建的是密集数组,索引0、1、2都有明确的元素值,数组长度为3,不存在空槽。const arr = new Array(3):创建的是稀疏数组,数组长度设为3,但索引0、1、2的位置是空槽(empty slot)——注意,空槽不是undefined,而是数组中根本不存在的索引位置。
2. 操作后的数组结构变化
第一段代码的完整流程:
- 初始状态:
new Array(3)→ 结构为[empty × 3],长度3,无实际元素。 - 三次
push后:数组长度变为6,结构是[empty × 3, 1, 2, 3](索引0、1、2是空槽,3=1,4=2,5=3)。 - 执行
arr.splice(0, 2):删除索引0、1的两个空槽,剩余数组结构变为[empty × 1, 1, 2, 3](原索引2的空槽留在索引0,原索引3-5的元素前移到索引1-3)。 - 访问
arr[0]时,因为该位置是空槽,返回undefined。
第二段代码的完整流程:
- 初始状态:
[1, 2, 3]→ 密集数组,索引0=1,1=2,2=3,长度3。 - 执行
arr.splice(0, 2):删除索引0、1的元素(1和2),剩余元素3前移到索引0,数组变为[3]。 - 访问
arr[0]直接返回3。
3. 关于“索引不从0开始”的问题
你遇到的“索引看似从splice位置开始”是稀疏数组的特性导致的:
稀疏数组的空槽不会被forEach、map等常规遍历方法处理,当你打印数组或用工具查看时,通常只会显示存在实际值的索引,看起来像是索引从某个位置开始,但实际上数组的索引依然从0开始——只是0到某个位置的索引是空槽,没有元素而已。比如第一段代码splice后的数组,console.log(arr)会显示[empty, 1, 2, 3],但它的长度是4,索引0确实存在(只是为空槽)。
避免此类问题的方法
如果需要创建指定长度的密集数组,不要用new Array(n),改用以下方式:
// 创建长度为3,每个元素为undefined的密集数组 const arr = Array.from({length: 3}); // 或者 const arr = new Array(3).fill(undefined);
这样创建的数组后续splice等操作行为会和字面量创建的数组完全一致。
内容的提问来源于stack exchange,提问作者JSmith
相关产品推荐
相关产品推荐

