JavaScript Array.fill创建二维数组时push结果异常的原因
异常原因
问题核心是Array.fill()对引用类型的填充逻辑存在特性,你初始化二维数组的写法导致两个子数组实际是同一个对象:
Array.fill()的规则:如果传入的填充值是数组、对象这类引用类型,方法不会给数组每一项创建独立的新副本,而是把同一个内存引用复制到所有下标位置,所有下标最终指向同一个对象。- 两个数组的本质差异:
- 数组
a用字面量[[null,null],[null,null]]初始化,两个子数组是完全独立的实例,内存地址互不干扰,修改其中一个不会影响另一个。执行a[0] === a[1]会返回false。 - 数组
b用Array(2).fill(Array(2))初始化时,参数里的Array(2)仅执行1次,只生成1个长度为2的稀疏数组实例,外层数组的b[0]和b[1]存的是同一个引用,指向这唯一的子数组。执行b[0] === b[1]会返回true。
- 数组
add(b)的实际执行逻辑:你预期map遍历会给两个独立子数组各追加1个null,但两次遍历操作的是同一个子数组:第一次遍历给这个子数组push一个null,长度从2变成3;第二次遍历又给同一个子数组push一个null,长度从3变成4。因为两个外层下标都指向这个长度为4的子数组,最终序列化结果就成了[[null,null,null,null],[null,null,null,null]]。
补充:最开始
JSON.stringify()打印a、b结果一致,是因为序列化时只会读取对象的结构和可枚举值,既不会识别内部引用是否重复,还会自动把数组空槽转换为null,因此完全掩盖了两个数组的本质差异。
正确初始化独立子数组的写法
不要直接用fill()填充引用类型,改用回调逻辑每次生成新的子数组实例即可:
// 推荐写法1:Array.from 配合工厂回调 function na(){ return Array.from({length: 2}, () => Array(2).fill(null)) } // 推荐写法2:先填充基础类型再map生成子数组 function na(){ return Array(2).fill(null).map(() => Array(2).fill(null)) }
内容的提问来源于stack exchange,提问作者João Otero
相关产品推荐
相关产品推荐

