循环数组仅保留最后值?JavaScript数组引用问题排查
为什么数组中对象的属性值被后续循环覆盖?
我写了一段JavaScript代码,想要生成包含数组的数组对象,但实际输出和期望不符:
代码示例
var cars = [{ a: 1 }, { a: 2 }]; var arr = [ { a: 0, name: "as" }, { a: 0, name: "aa" }, ]; var fin = []; for (let i in cars) { const asd = cars[i].a; for (let j in arr) { if (arr[j].name == "as") { arr[j].a = asd; } } fin.push(arr); } console.log(fin);
实际输出
[[{ a: 2, name: "as" },{ a: 0, name: "aa" }],[{ a: 2, name: "as" },{ a: 0, name: "aa" }]]
期望输出
[[{ a: 1, name: "as" },{ a: 0, name: "aa" }],[{ a: 2, name: "as" },{ a: 0, name: "aa" }]]
为什么fin[0][0].a没有保留1,反而被改成了2?
原因分析
这是JavaScript引用类型的特性导致的:
arr是数组,属于引用类型,在内存中存储的是一个地址,而非具体值。- 每次循环调用
fin.push(arr)时,并没有复制arr的内容存入,而是把arr的内存地址存进了fin数组。 - 第一次循环修改
arr中name="as"的对象a值为1,将arr的地址push到fin;第二次循环又修改同一个arr里的对象a值为2,再push同一个地址。 - 最终
fin里的两个元素都指向内存中同一个arr数组,打印时自然都是最后一次修改后的结果。
解决方法
每次循环时,创建arr的浅拷贝(因数组元素是对象,需同时复制对象),修改拷贝后的数组,再将其push到fin。
修改后的代码如下:
var cars = [{ a: 1 }, { a: 2 }]; var arr = [ { a: 0, name: "as" }, { a: 0, name: "aa" }, ]; var fin = []; for (let i in cars) { const asd = cars[i].a; // 复制原数组及内部对象 const newArr = arr.map(item => ({ ...item })); for (let j in newArr) { if (newArr[j].name == "as") { newArr[j].a = asd; } } fin.push(newArr); } console.log(fin);
这里用arr.map(item => ({ ...item }))生成原数组的浅拷贝:map创建新数组,{...item}用对象展开语法复制每个对象的属性,确保每次循环操作的是独立的数组和对象,不会互相干扰。
内容的提问来源于stack exchange,提问作者Anas Al-Saadi
相关产品推荐
相关产品推荐

