如何追踪JavaScript for循环?二维数组生成代码异常排查
二维数组生成代码的异常原因分析
先看出现问题的代码:
function zeroArray(m, n) { // Creates a 2-D array with m rows and n columns of zeroes let newArray = []; let row = []; for (let i = 0; i < m; i++) { // Adds the m-th row into newArray for (let j = 0; j < n; j++) { // Pushes n zeroes into the current row to create the columns row.push(0); } // Pushes the current row, which now has n zeroes in it, to the array newArray.push(row); } return newArray; } let matrix = zeroArray(3, 2); console.log(JSON.stringify(matrix));
当调用zeroArray(3, 2)时,预期输出是[[0,0], [0,0,0,0], [0,0,0,0,0,0]],但实际输出是[[0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0]],下面一步步追踪循环执行过程:
循环执行步骤
初始化:newArray = [],row = [],m=3,n=2
外层循环i=0
- 内层循环j从0到1:
- j=0:
row.push(0)→row = [0] - j=1:
row.push(0)→row = [0, 0]
- j=0:
- 执行
newArray.push(row)→newArray = [[0, 0]] - 注意:这里push的是
row数组的引用,不是复制出的新数组,newArray里的元素和row指向同一个内存地址。
- 内层循环j从0到1:
外层循环i=1
- 内层循环j从0到1:
- j=0:
row.push(0)→row = [0, 0, 0] - j=1:
row.push(0)→row = [0, 0, 0, 0]
- j=0:
- 执行
newArray.push(row)→newArray = [[0,0,0,0], [0,0,0,0]] - 此时newArray里的两个元素都是指向同一个row数组的引用,所以row变化时,两个元素都会同步更新。
- 内层循环j从0到1:
外层循环i=2
- 内层循环j从0到1:
- j=0:
row.push(0)→row = [0, 0, 0, 0, 0] - j=1:
row.push(0)→row = [0, 0, 0, 0, 0, 0]
- j=0:
- 执行
newArray.push(row)→newArray = [[0,0,0,0,0,0], [0,0,0,0,0,0], [0,0,0,0,0,0]] - 三个元素全部指向同一个row数组,所以最终打印时,所有行都是经过三次内层循环添加元素后的row数组。
- 内层循环j从0到1:
异常原因
row数组只在函数开头初始化了一次,每次向newArray中push的都是同一个数组的引用,而不是新创建的数组。每次内层循环都会往这个共享的row数组里添加元素,导致最后所有行都指向这个被反复修改的数组,最终呈现出全是相同长数组的结果。
修复方案
把row的声明移到外层循环内部,每次外层循环都创建一个新的row数组,这样每次push到newArray的都是独立的数组:
function zeroArray(m, n) { let newArray = []; for (let i = 0; i < m; i++) { let row = []; // 每次循环创建新的空数组 for (let j = 0; j < n; j++) { row.push(0); } newArray.push(row); } return newArray; } let matrix = zeroArray(3, 2); console.log(JSON.stringify(matrix)); // 输出 [[0,0],[0,0],[0,0]]
内容的提问来源于stack exchange,提问作者hassan Shamel
相关产品推荐
相关产品推荐

