在JavaScript开发中,我们经常需要在循环里生成不同的对象并添加到数组中,但很多时候会发现最终数组里的所有元素都变成了最后一个生成的对象,这和预期的结果完全不符。这种问题在for循环、forEach循环等常见循环场景中都很容易出现,很多新手开发者第一次遇到时会感到困惑,不知道问题出在哪里。

问题复现
我们先通过一个简单的for循环示例来复现这个问题,代码如下:
// 定义一个空数组
let arr = [];
// 定义一个基础对象
let obj = {
name: '',
age: 0
};
// 循环向数组添加对象
for (let i = 0; i < 3; i++) {
obj.name = '用户' + i;
obj.age = 20 + i;
arr.push(obj);
}
// 打印数组结果
console.log(arr);
我们预期的结果是数组里有三个不同的对象,分别是{name: '用户0', age: 20}、{name: '用户1', age: 21}、{name: '用户2', age: 22},但实际打印出来的结果是三个对象完全一样,都是最后一个{name: '用户2', age: 22}。
问题产生的原因
这个问题的核心原因是JavaScript中对象属于引用类型。引用类型的变量存储的不是实际的数据值,而是数据在内存中的地址引用。在上面的代码中,我们只在循环外部定义了一个obj对象,这个obj始终指向同一个内存地址。
循环中我们每次修改的都是同一个obj对象的属性,然后把obj的引用添加到数组里。因为数组里存储的都是同一个内存地址的引用,所以不管后面怎么修改obj的属性,数组里所有元素指向的都是同一个对象,最终自然都会显示最后一次修改的结果。
解决方案
方案一:循环内每次创建新对象
最直接的方法就是在循环内部每次都创建一个新的对象,这样每个对象都有独立的内存地址,修改互不影响。代码如下:
let arr = [];
for (let i = 0; i < 3; i++) {
// 每次循环都创建新的对象
let obj = {
name: '用户' + i,
age: 20 + i
};
arr.push(obj);
}
console.log(arr);
方案二:使用Object.assign复制对象
如果有一个基础的对象模板,也可以使用Object.assign方法在每次循环时复制出一个新的对象,避免引用同一个对象。代码如下:
let arr = [];
let baseObj = {
name: '',
age: 0
};
for (let i = 0; i < 3; i++) {
// 复制基础对象生成新对象
let newObj = Object.assign({}, baseObj, {
name: '用户' + i,
age: 20 + i
});
arr.push(newObj);
}
console.log(arr);
方案三:使用扩展运算符复制对象
扩展运算符也可以实现对象的浅拷贝,生成新的对象实例,同样可以解决这个问题。代码如下:
let arr = [];
let baseObj = {
name: '',
age: 0
};
for (let i = 0; i < 3; i++) {
// 用扩展运算符复制对象
let newObj = {
...baseObj,
name: '用户' + i,
age: 20 + i
};
arr.push(newObj);
}
console.log(arr);
注意事项
上面的方案都是浅拷贝,如果对象里还有嵌套的引用类型属性,修改嵌套属性还是可能出现类似的问题。如果处理的是深层嵌套的对象,需要使用深拷贝的方法,比如自己实现深拷贝函数,或者使用JSON.parse(JSON.stringify(obj))的方式(注意这种方式不能处理函数、正则等特殊类型)。
另外在forEach、map等数组遍历方法中,如果出现类似的问题,原因和for循环是一致的,都可以用上述的方法解决。只要保证每次添加到数组的是独立的新对象,就可以避免只返回最后一个值的问题。
JavaScript循环数组对象引用类型修改时间:2026-07-20 08:48:19