JavaScript嵌套数组对象数组生成时数据丢失问题排查
问题:嵌套数组的对象数组数据丢失
尝试创建包含嵌套数组的对象数组,但最后一步出现数据丢失情况,代码如下:
JavaScript代码
const args_arr = []; const options_arr = []; let options = ''; let text = ""; for (let i = 0; i < 5; i++) { for (let j = 0; j < 5; j++) { if (i === j) { args_arr.push(true); } else { args_arr.push(false); } } text += args_arr + "<br>"; options = { op1: true, op2: false, args: ['visible'] }; text += JSON.stringify(options) + "<br>"; options.args.push(args_arr); text += JSON.stringify(options) + "<br>"; options_arr.push(options); args_arr.length = 0; } text += '<br>' + JSON.stringify(options_arr) + "<br>"; document.getElementById("demo").innerHTML = text;
HTML代码
<pre id="demo"></pre>
运行时中间步骤输出正常,但最终options_arr里的所有对象的args数组中,visible后的子数组都变成了空数组,结果如下:
true,false,false,false,false {"op1":true,"op2":false,"args":["visible"]} {"op1":true,"op2":false,"args":["visible",[true,false,false,false,false]]} false,true,false,false,false {"op1":true,"op2":false,"args":["visible"]} {"op1":true,"op2":false,"args":["visible",[false,true,false,false,false]]} false,false,true,false,false {"op1":true,"op2":false,"args":["visible"]} {"op1":true,"op2":false,"args":["visible",[false,false,true,false,false]]} false,false,false,true,false {"op1":true,"op2":false,"args":["visible"]} {"op1":true,"op2":false,"args":["visible",[false,false,false,true,false]]} false,false,false,false,true {"op1":true,"op2":false,"args":["visible"]} {"op1":true,"op2":false,"args":["visible",[false,false,false,false,true]]} [{"op1":true,"op2":false,"args":["visible",[]]},{"op1":true,"op2":false,"args":["visible",[]]},{"op1":true,"op2":false,"args":["visible",[]]},{"op1":true,"op2":false,"args":["visible",[]]},{"op1":true,"op2":false,"args":["visible",[]]}]
问题原因
这是引用类型的共享引用导致的问题:
- 全程复用同一个
args_arr数组,每次执行options.args.push(args_arr)时,并没有复制数组内容,而是把这个数组的内存引用塞进了options.args里。 - 循环最后执行
args_arr.length = 0清空数组时,所有已经推入options_arr的options对象里的args子数组,因为指向同一个args_arr引用,所以都会跟着变成空数组。
解决方案
有两种简单的修复方式:
方法1:每次循环创建新的args_arr
把args_arr的声明移到外层循环内部,每次循环都新建一个数组,避免共享引用:
const options_arr = []; let options = ''; let text = ""; for (let i = 0; i < 5; i++) { // 每次循环新建数组 const args_arr = []; for (let j = 0; j < 5; j++) { if (i === j) { args_arr.push(true); } else { args_arr.push(false); } } text += args_arr + "<br>"; options = { op1: true, op2: false, args: ['visible'] }; text += JSON.stringify(options) + "<br>"; options.args.push(args_arr); text += JSON.stringify(options) + "<br>"; options_arr.push(options); } text += '<br>' + JSON.stringify(options_arr) + "<br>"; document.getElementById("demo").innerHTML = text;
方法2:推入数组的副本而非引用
在options.args.push时,传入args_arr的副本,后续修改原数组不会影响副本:
const args_arr = []; const options_arr = []; let options = ''; let text = ""; for (let i = 0; i < 5; i++) { for (let j = 0; j < 5; j++) { if (i === j) { args_arr.push(true); } else { args_arr.push(false); } } text += args_arr + "<br>"; options = { op1: true, op2: false, args: ['visible'] }; text += JSON.stringify(options) + "<br>"; // 推入数组副本,用扩展运算符或者slice()都可以 options.args.push([...args_arr]); // 或者 options.args.push(args_arr.slice()); text += JSON.stringify(options) + "<br>"; options_arr.push(options); args_arr.length = 0; } text += '<br>' + JSON.stringify(options_arr) + "<br>"; document.getElementById("demo").innerHTML = text;
两种方法都能让options_arr里的每个对象保留正确的嵌套数组数据。
内容的提问来源于stack exchange,提问作者MrBlindMouse
相关产品推荐
相关产品推荐

