js/ts二维数组更新元素时所有列都更新了
2022-12-03 本文已影响0人
tianxiawuzhe
想实现的目标
在js/ts(typescript)项目,经常会遇到使用二维数组的场景,但js/ts中没有直接的二维数组可以使用,间接实现方法是嵌套一维数组。
现在项目需初始化NxN的二维数组,且每个元素为0,然后程序会根据逻辑要求,更新其中的某个元素值。这有点像是NxN的稀疏矩阵。
初版实现
有了上述需求,很容易写出初始化的语句:
let N = 3;
let arr1 = new Array(N).fill(new Array(N).fill(0));
...
arr1[1][2] = 1;
...
代码很简洁,先new Array(N)出N行,再在N行中填充N列,N列同样使用new Array方式进行创建并初始化为0,在创建完后通过输出arr1值,可以看出,确实是生成NxN的0矩阵:
image.png
但是,执行完arr1[1][2]这行语句后,arr1值变成了:
image.png
发生了什么??二维数组还能按列更新?感觉像是行下标不起作用?
原因
经过再次仔细上述简短的代码,左看右看还是没有想到原因在哪里,最后通过浏览器的F12工具验证: image.png把问题范围缩小到
new Array(N).fill(new Array(N).fill(0));
这条语句上:原来是JS引用导致的问题!!!
这条语句,应该先是创建了N行数组,接着调用fill函数时,先计算N列的创建并初始化为N列全0数组,然后再把N列数组传入到原fill函数中,此时传入的N列是同一个对象,因此N行数组的每一行的子数组都指向了同一个N列,也就当更新某一个元素时,所有列都变化了,因为整个数组实际就1行N列。此语句应等效于(仅为推测,未查看底层js实际执行过程哈):
let n_cols = new Array(N).fill(0);
let arr1 = new Array(N).fill(n_cols);
整改
let N = 3;
let arr1 = new Array(N).fill(0).map((val) => new Array(N).fill(0));
...
arr1[1][2] = 1;
...
这次就成功啦:
image.png
注意:
需先对N行使用fill(0)填充后,map才有效果哦!!!