循环赋值二维数组仅存最后值:如何存入变量当前值而非引用?
问题本质:引用类型的传递特性
在JavaScript中,数组属于引用类型,而非值类型。你每次调用rangeArray.push(rowArray)时,并没有把rowArray的当前值复制进去,而是把它在内存中的引用地址存到了rangeArray里。整个循环过程中,你始终在修改同一个rowArray的内容,所有已经存入rangeArray的引用都会指向这个被反复修改的数组,最终所有元素自然都是最后一次修改后的结果。
触发场景
这种问题会在以下场景出现:
- 循环中重复使用同一个引用类型变量(数组、对象等),并多次将其添加到另一个容器中
- 后续代码会修改这个引用类型变量的内部状态
最优解决方法
核心思路是:每次向rangeArray中添加时,存入的是当前数组的副本,而非原数组的引用。以下是几种可靠的实现方式:
方法1:每次循环内创建新数组
把rowArray的声明放到外层循环内部,让每次循环都生成一个全新的数组,从根源避免引用复用:
var rangeArray = []; for (k = 0; k < 5; k++){ // 每次循环新建一个数组,不存在引用共享问题 var rowArray = []; for (var i = 0; i < 6; i++){ rowArray[i] = ((i+1) *(k+1)); } rangeArray.push(rowArray); } Logger.log(rangeArray);
方法2:使用数组拷贝方法生成副本
如果需要保留原数组的初始结构,每次push前可以创建当前rowArray的浅拷贝,常用的拷贝方式有三种:
slice():无参数调用时返回原数组的浅拷贝[...rowArray]:扩展运算符快速生成拷贝Array.from(rowArray):通过Array.from创建拷贝
修改后的代码示例:
var rowArray = [".", ".", ".", ".", ".", "."]; var rangeArray = []; for (k = 0; k < 5; k++){ for (var i = 0; i < 6; i++){ rowArray[i] = ((i+1) *(k+1)); } // 推入当前数组的副本,而非原引用 rangeArray.push(rowArray.slice()); // 也可以用扩展运算符:rangeArray.push([...rowArray]); } Logger.log(rangeArray);
方法3:直接在循环中生成目标数组(更简洁)
可以省略单独的rowArray变量,直接在每次循环里生成目标行数组:
var rangeArray = []; for (k = 0; k < 5; k++){ // 用Array.from直接生成当前行的数组并推入 rangeArray.push(Array.from({length:6}, (_, i) => (i+1)*(k+1))); } Logger.log(rangeArray);
为什么临时方法不可靠?
你用toString().split(",")的方式本质是一种取巧的hack,存在明显缺陷:
- 如果数组元素本身包含逗号(比如字符串
"a,b"),拆分后会被错误地分割成两个元素 - 数值会被转换为字符串类型,后续可能需要额外的类型转换操作
- 性能远不如直接的数组拷贝方法
内容的提问来源于stack exchange,提问作者Андрей Косенко
相关产品推荐
相关产品推荐

