在 JavaScript 中,合并对象指的是将一个或多个源对象的属性复制到目标对象中。合并后,目标对象将包含其原有的属性以及从源对象复制过来的属性。如果源对象和目标对象有同名的属性,则通常源对象的属性会覆盖目标对象的属性。
在 JavaScript 中,常见的合并对象的方式有以下 3 种。
- 手动复制属性。
- 使用 Object.assign()。
- 使用展开运算符。
手动复制属性来合并对象
在 JavaScript 中,合并对象最简单的方式就是手动遍历源对象的属性,并逐一复制到目标对象。
示例 1:手动复杂属性
const obj1 = { "name": "阿莫", "age": 18 };
const obj2 = { "city": "广州", "age": 20 }; // 注意:age 属性会覆盖
const result = {};
// 复制第一个对象
for (let key in obj1) {
if (obj1.hasOwnProperty(key)) {
result[key] = obj1[key];
}
}
// 复制第二个对象
for (let key in obj2) {
if (obj2.hasOwnProperty(key)) {
result[key] = obj2[key];
}
}
console.log(result);运行结果如下。
{ name: '阿莫', age: 20, city: '广州' }分析:
在这个例子中,我们首先使用 for...in 循环来遍历 obj1 的每个属性,然后将其所有属性复制到 result 中。其中,hasOwnProperty() 方法用于判断当前属性是否 “自身属性”。
同样地,我们再复制 obj2 的属性。由于 obj2 后复制,它的 age 属性 (20) 覆盖了 obj1 的 age 属性 (18)。
虽然手动复制属性可以合并两个对象,但这种方式比较繁琐,在实际开发中并不推荐。
使用 Object.assign() 来合并对象
Object.assign() 是 ES6+ 引入的一个方法,用于将所有可枚举的自身属性的值从一个或多个源对象复制到目标对象。
语法:
Object.assign(target, source1, source2, ...);说明:
Object.assign() 方法的第一个参数是目标对象,随后的参数是源对象(可以是一个,也可以是多个)。
源对象的属性从左到右依次复制。如果多个源对象有同名属性,则后面的源对象会覆盖前面的。
注意:
- Object.assign() 实现的是浅复制,而不是深复制,如果属性值是对象或数组,此时复制的是引用而不是新的副本。
- Object.assign() 会修改目标对象,并返回修改后的目标对象。
示例 2:使用 Object.assign() 合并对象
const obj1 = { "name": "阿莫", "age": 18 };
const obj2 = { "city": "广州", "age": 20 }; // 注意:age 属性会覆盖
const result = Object.assign({}, obj1, obj2); // 合并到一个新对象
console.log(result);运行结果如下。
{ name: '阿莫', age: 20, city: '广州' }分析:
Object.assign({}, obj1, obj2); 表示将 obj1 和 obj2 复制到一个新的空对象中。可能小伙伴会问:“为什么要复制到一个空对象中呢?使用 Object.assign(obj1, obj2); 进行复制不也可以吗?”
实际上,Object.assign(obj1, obj2); 会修改 obj1 对象,这并不是我们预期的结果。小伙伴们可以自行测试一下下面代码,看看结果就知道了。
const obj1 = { "name": "阿莫", "age": 18 };
const obj2 = { "city": "广州", "age": 20 };
const result = Object.assign(obj1, obj2);
console.log(obj1);
console.log(obj2);
console.log(result);示例 3:Object.assign() 实现的是浅复制
const objA = {
"a": 1,
"nested": { "x": 10 }
};
const objB = {};
Object.assign(objB, objA);
console.log(objB);
console.log(objB.nested === objA.nested); // nested 是同一个对象引用运行结果如下。
{ a: 1, nested: { x: 10 } }
true分析:
尽管 objA 的属性被复制到了 objB,但 nested 属性内部的对象并没有被重新创建,objB.nested 和 objA.nested 指向的是同一个对象。因此,修改 objB.nested.x 也会影响 到 objA.nested.x。
使用 “展开运算符” 来合并对象
展开运算符也是 ES6+ 中引入的,它提供了一种非常简洁的方式来合并对象的自身可枚举属性。
语法:
let mergedObject = { ...obj1, ...obj2};说明:
展开运算符的使用非常简单,它使用三个点(...)后面跟上要合并的对象。然后属性从左到右依次展开和复制。如果多个对象有同名属性,后面的会覆盖前面的。
展开语法会创建一个新的对象,不会修改原始对象。
提示: 展开运算符实现的同样也是浅复制,而不是深复制。
示例 4:使用展开语法合并对象
const obj1 = { "name": "阿莫", "age": 18 };
const obj2 = { "city": "广州", "age": 20 };
const result = {...obj1, ...obj2};
console.log(result);运行结果如下。
{ name: '阿莫', age: 20, city: '广州' }分析:
在这个例子中,展开运算符会将 obj1 和 obj2 的所有属性展开,并收集到一个新的对象 result 中。然后对于同名的属性,后面的会覆盖前面的。
在实际项目开发中,我们推荐使用展开语法(...)或 Object.assign() 来合并对象,它们更简洁且功能更强大。如果需要深复制,则需要使用其他方法,比如 “JSON.stringify() + JSON.parse()” 或者专门的库。
