Object.assign() 语法
Object.assign() 是 JavaScript 中一个静态方法,它用于将多个对象合并成一个对象。
Object.assign() 会将所有可枚举的自身属性的值从一个或多个源对象复制到目标对象,然后返回目标对象。
语法:
Object.assign(obj1, obj2, ..., objN)说明:
Object.assign() 方法会将 obj2、obj3、...、objN 合并到 obj1 中去,然后返回合并后的对象。
对于 Object.assign(),小伙伴们要清楚以下几点。
- 执行的是浅拷贝:Object.assign() 执行的是浅拷贝。也就是说,如果源对象的属性值是另一个对象的引用(比如一个嵌套对象或数组),那么复制到目标对象的只是这个引用,而不是被引用的对象本身。因此,修改目标对象中这个引用属性的值,会影响到源对象。
- 会覆盖相同属性:如果源对象和目标对象有相同的属性键,源对象的属性值会覆盖目标对象的属性值。
- 只复制可枚举的自身属性:Object.assign() 只会复制源对象中那些可枚举(enumerable: true)的自身属性(非继承属性)。Symbol 属性也会被复制。
- 处理原始值:如果目标对象不是对象,Object.assign() 会尝试将其转换为对象。对于原始值(字符串、数字、布尔值),它们会被包装成对象。但由于它们是不可变的,最终返回的仍然是包装后的对象。null 和 undefined 作为目标对象会抛出 TypeError。源对象中的原始值会被跳过。
- getter 和 setter:Object.assign() 在复制属性时,会调用源对象属性的 getter(如果存在),然后将获取到的值作为普通属性(非 setter)复制到目标对象。
注意:
- assign() 是一个静态方法,它只能被类名(即 Object)调用,而无法被实例调用。
- Object.assign() 方法会修改第 1 个对象。不过它也是有返回值的,它的返回值本质上也是合并后的第 1 个对象。
Object.assign() 摘要
| 属于 | JavaScript Object 对象 |
|---|---|
| 使用频率 | 高 |
| 官方文档 | 查看 |
| MDN | 查看 |
Object.assign() 示例
接下来,我们通过几个简单的例子来讲解一下 Object.assign() 方法是如何使用的。
示例 1:Object.assign() 合并 2 个对象
const obj1 = { a: 1, b: 2 };
const obj2 = { c: 3, d: 4 };
Object.assign(obj1, obj2);
console.log(obj1);
console.log(obj2);运行结果如下。
{a: 1, b: 2, c: 3, d: 4}
{c: 3, d: 4}分析:
在这个例子中,Object.assign() 方法会将 obj2 合并到 obj1 中。特别注意一点,Object.assgin() 方法会改变第 1 个对象,也就是说 obj1 此时是已经被改变了的。但是它不会改变后面的对象,此时 obj2 还是原来的对象。
示例 2:Object.assign() 有返回值
const obj1 = { a: 1, b: 2 };
const obj2 = { c: 3, d: 4 };
const result = Object.assign(obj1, obj2);
console.log(obj1);
console.log(result);
console.log(obj1 === result);运行结果如下。
{ a: 1, b: 2, c: 3, d: 4 }
{ a: 1, b: 2, c: 3, d: 4 }
true分析:
从结果可以看到,Object.assign() 方法返回的结果本质上和合并后的 obj1 是完全相等的。不过在实际开发中,我们更倾向于不使用返回值的方式,也就是使用示例 1 的方式。
示例 3:Object.assign() 合并 n 个对象
const obj1 = { a: 1, b: 2 };
const obj2 = { c: 3, d: 4 };
const obj3 = { e: 5, f: 6 };
Object.assign(obj1, obj2, obj3);
console.log(obj1);运行结果如下。
{a: 1, b: 2, c: 3, d: 4, e: 5, f: 6}分析:
无论 Object.assign() 合并多少个对象,都是将其他对象合并到第 1 个对象中去。
示例 4:合并的对象存在相同属性(1)
const obj1 = { a: 1, b: 2 };
const obj2 = { b: 3, d: 4 };
Object.assign(obj1, obj2);
console.log(obj1);运行结果如下。
{a: 1, b: 3, d: 4}分析:
对于 Object.assign() 方法来说,如果两个对象有相同的属性,那么后面对象的属性值会覆盖前面对象的属性值。我们再来多看一个例子。
示例 5:合并的对象存在相同属性(2)
const obj1 = { a: 1, b: 2 };
const obj2 = { b: 3, d: 4 };
const obj3 = { b: 5, f: 6 };
Object.assign(obj1, obj2, obj3);
console.log(obj1);运行结果如下。
{a: 1, b: 5, d: 4, f: 6}深入了解 Object.assign()
Object.assign() 方法实现的是浅拷贝,而不是深拷贝。对于浅拷贝和深拷贝,它们之间的区别如下。
- 浅拷贝:如果属性是基本类型,那么则会复制它的值;如果属性是引用类型,则会复制它的引用。
- 深拷贝:不管属性是基本类型还是引用类型,都只是复制它的值。
示例 6:Object.assign() 实现浅拷贝
const obj1 = { a: 1, b: 2 };
const obj2 = {
c: 3,
name: {
first: "Jack",
last: "Mo"
}
}
Object.assign(obj1, obj2);
obj2.name.first = "Lucy";
console.log(obj1.name.first);
console.log(obj2.name.first);运行结果如下。
Lucy
Lucy分析:
对于这个例子来说,由于 Object.assign() 方法实现的是浅拷贝,因此当我们改变 obj2.name.first 的值,此时 obj1.name.first 的值也会一起跟着改变。或者改变 obj1.name.first 的值,obj2.name.first 也会跟着改变,小伙伴可以自己试一下。
对于浅拷贝和深拷贝,用最通俗易懂的话来说就是:如果是浅拷贝,那么前后两个对象 “可能” 还会有瓜葛;如果是深拷贝,那么前后两个对象一定毫无瓜葛。
示例 7:Object.assign() 拷贝对象
function clone(obj) {
return Object.assign({}, obj);
}
const obj1 = {
name: {
first: "Jack",
last: "Mo"
},
age: 24
};
const obj2 = clone(obj1);
obj2.name.first = "Lucy";
console.log(obj1.name.first);
console.log(obj2.name.first);运行结果如下。
Lucy
Lucy分析:
Object.assign() 这种方式,只适合拷贝一些简单对象,但是不适合拷贝复杂对象。这里只是简单了解一下,在真实的开发中,我们很少会用 Object.assign() 方法来拷贝一个对象的。
示例 8:Object.assign() 处理数组
const arr1 = [1, 2, 3];
const arr2 = [4, 5];
Object.assign(arr1, arr2);
console.log(arr1);运行结果如下。
[4, 5, 3]分析:
之所以输出 [4,5,3],是因为 Object.assign() 方法把数组 arr1、arr2 看成是下面这样的对象。
const arr1 = {"0": 1, "1": 2, "2": 3};
const arr2 = {"0": 4, "1": 5};此时 arr2 的 0 号属性覆盖了 arr1 的 0 号属性,arr2 的 1 号属性覆盖了 arr1 的 1 号属性,以此类推。不过使用 Object.assign() 处理数组这种情况很少见到,小伙伴们简单了解一下就可以了。
Object.assign() 的应用场景
在实际开发中,Object.assgin() 方法也是非常有用的,它可以用于以下 4 个方面。
- 给对象添加属性。
- 给对象添加方法。
- 给对象属性设置默认值。
- 合并对象。
示例 9:Object.assign() 给对象添加属性
function Person(name, gender, age) {
Object.assign(this, { name, gender, age });
}
const p = new Person("Jack", "male", 24);
console.log(p);运行结果如下。
{ name: "Jack", gender: "male", age: 24 }分析:
Object.assign(this, {name, gender, age}) 表示将 name、gender、age 属性添加到 Person 对象的 this 中。其中,下面 2 种方式是等价的。
// 方式1
function Person(name, gender, age) {
Object.assign(this, { name, gender, age });
}
// 方式2
function Person(name, gender, age) {
this.name = name;
this.gender = gender;
this.age = age;
}示例 10:Object.assign() 给对象添加方法
function Person(name, age) {
this.name = name;
this.age = age;
}
Object.assign(Person.prototype, {
getName() {
return this.name;
},
getAge() {
return this.age;
}
});
const p = new Person("Jack", 24);
console.log(p.getName());运行结果如下。
Jack分析:
对于这个例子来说,下面 2 种方式是等价的。
// 方式1
Object.assign(Person.prototype, {
getName() {
return this.name;
},
getAge() {
return this.age;
}
});
// 方式2
Person.prototype.getName = function() {
return this.name;
}
Person.prototype.getAge = function() {
return this.age;
}示例 11:Object.assign() 给对象属性设置默认值
function createBox(box) {
const defaultBox = {
radius: 10,
color: "red"
};
return Object.assign({}, defaultBox, box);
}
const box = createBox({ radius: 20 });
console.log(box);运行结果如下。
{ radius: 20, color: "red" }分析:
使用 Object.assign() 方法来设置对象属性的默认值,基本上就是先接受一个不完整的对象,然后填充缺失的值。
示例 12:Object.assign() 合并对象
function findBook(book) {
const { tag, price } = book;
const options = {
name: "从0到1"
};
if (tag) {
Object.assign(options, { tag });
}
if (price) {
Object.assign(options, { price });
}
console.log(options);
// 接下来可以使用options作为查询数据库的条件
}
const book = {
price: 89
};
findBook(book);运行结果如下。
{ name: "从0到1", price: 89 }分析:
在前后端交互的时候,前端传过来不确定数量的参数,然后希望从数据库查询一些信息。此时我们就可以使用 Object.assign() 方法来将这些参数合并成一个对象,最后再把这个对象传递给后端 service 层进行处理。
提示: 在现代 JavaScript (ES2018+) 开发中,我们更倾向于使用 “对象扩展运算符” 来代替 Object.assign()。主要是扩展运算符这种方式更加简洁,比如:const newObj = { ...obj1, ...obj2 };。
