Object.assign() 与 扩展操作符(...)

参考资料:

Object.assign() 与 扩展操作符(…)

React 提倡不可变的数据结构。因此你不应该改变一个对象(或者直接改变状态)。
更好的做法是基于现在拥有的资源来创建一个新的对象。这样就没有任何对象被改变了。
这样做的好处是数据结构将保持不变,因为你总是返回一个新对象,而之前的对象保持不变。

简单说就是,不要直接修改对象属性,而是直接创建新的对象。
实现创建一个新的对象有两种方法,即:Object.assign() 与 扩展操作符(…)

Object.assign()

Object.assign() 函数来到达这样的目的。它把接收的第一个参数作为目标对象,后面的所有参数作为源对象。然后把所有的源对象合并到目标对 象中。
只要把目标对象设置成一个空对象,我们就得到了一个新的对象。这种做法是拥抱 不变性的,因为没有任何源对象被改变。

React 中的使用:

1
2
3
  this.setState({
result: Object.assign({}, this.state.result, { hits: updatedHits })
});

其他使用方法

复制一个对象

1
2
3
var obj = { a: 1 };
var copy = Object.assign({}, obj);
console.log(copy); // { a: 1 }

深拷贝问题:

针对深拷贝,需要使用其他方法,因为 Object.assign()拷贝的是属性值。假如源对象的属性值是一个指向对象的引用,它也只拷贝那个引用值。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
let obj1 = { a: 0 , b: { c: 0}};
let obj2 = Object.assign({}, obj1);

// 当修改 obj2.b.c 发现 obj1、obj2 的属性都被修改了,因为他们保存的是对象的同一个引用
obj2.b.c = 3;
console.log(JSON.stringify(obj1)); // { a: 1, b: { c: 3}}
console.log(JSON.stringify(obj2)); // { a: 2, b: { c: 3}}


// 正确实现深拷贝的方式
obj1 = { a: 0 , b: { c: 0}};
let obj3 = JSON.parse(JSON.stringify(obj1));
obj1.a = 4;
obj1.b.c = 4;
console.log(JSON.stringify(obj3)); // { a: 0, b: { c: 0}}

合并对象

1
2
3
4
5
6
7
var o1 = { a: 1 };
var o2 = { b: 2 };
var o3 = { c: 3 };

var obj = Object.assign(o1, o2, o3);
console.log(obj); // { a: 1, b: 2, c: 3 }
console.log(o1); // { a: 1, b: 2, c: 3 }, 注意目标对象自身也会改变。

合并具有相同属性的对象

1
2
3
4
5
6
var o1 = { a: 1, b: 1, c: 1 };
var o2 = { b: 2, c: 2 };
var o3 = { c: 3 };

var obj = Object.assign({}, o1, o2, o3);
console.log(obj); // { a: 1, b: 2, c: 3 }

扩展操作符(…)

由三个点组成: ... 。当使用它时,数组 或对象中的每一个值都会被拷贝到一个新的数组或对象。

React 中使用

1
2
3
  this.setState({
result: { ...this.state.result, hits: updatedHits }
});