FCC练习题:JavaScript二维数组循环行为异常原因排查
问题原因分析
你遇到的问题本质是JavaScript中引用类型的赋值特性导致的:
- 数组属于引用类型,你在函数最外层声明的
let row = [],全程只有这一个数组对象存在。你每次调用newArray.push(row)时,推入的并不是row数组的独立副本,而是指向同一个row对象的内存地址引用。 - 后续你对同一个row数组做的所有修改,都会同步反映到所有指向这个地址的引用上,也就是你debug时看到的newArray里已有元素同步更新的现象。
循环过程拆解
我们可以一步步还原3次外层循环的实际执行逻辑:
- 第一次外层i=0循环:内层循环给row推入2个0,row变为
[0,0],将row的引用推入newArray,此时newArray为[<指向row的引用>] - 第二次外层i=1循环:内层循环给同一个row再推入2个0,row变为
[0,0,0,0],newArray里的第一个元素因为指向同一个内存地址,同步更新为[0,0,0,0],之后再把同一个引用推入newArray,现在newArray里两个元素都指向同一个row - 第三次外层i=2循环:内层循环再给row推入2个0,row变为
[0,0,0,0,0,0],newArray里前两个元素同步更新,再推入同一个引用,最终三个元素全部指向同一个长度为6的数组,就出现了你看到的输出结果。
解决方案
方案1:生成标准m行n列的全0矩阵
如果你的预期是得到3行2列的全0矩阵[[0,0],[0,0],[0,0]],只需要把row数组的声明放到外层for循环内部,每次循环都创建全新的独立数组即可:
function zeroArray(m, n) { let newArray = []; for (let i = 0; i < m; i++) { // 每次外层循环都创建全新的row数组,避免引用共享 let row = []; for (let j = 0; j < n; j++) { row.push(0); } newArray.push(row); } return newArray; }
方案2:生成你描述的递增长度预期输出
如果你的预期就是你提到的每行长度依次递增n个0的结果[[0,0],[0,0,0,0],[0,0,0,0,0,0]],不需要改row的声明位置,只需要在推入newArray时传递row的浅拷贝即可:
function zeroArray(m, n) { let newArray = []; let row = []; for (let i = 0; i < m; i++) { for (let j = 0; j < n; j++) { row.push(0); } // 推入row的浅拷贝,后续修改原row不会影响已推入的元素 newArray.push([...row]); } return newArray; }
内容的提问来源于stack exchange,提问作者Z H
相关产品推荐
相关产品推荐

