JavaScript的深拷贝和浅拷贝

原文:Deep Copy vs Shallow Copy in JavaScript

在JavaScript中,经常会听说“深克隆”和“浅克隆”,也叫做浅拷贝和浅拷贝。本文介绍了其含义及示例。

复制一个JavaScript的对象,可以是深拷贝或浅拷贝。其中的不同之处在于,深拷贝会递归拷贝所有的嵌套对象,比如lodash的cloneDeep()函数Object.assign()函数可以浅拷贝对象。

1
2
3
4
5
6
const obj = { answer: 42 };
// `Object.assign()` 函数常用于浅拷贝对象
const copy = Object.assign({}, obj);

++copy.answer; // 43
obj.answer; // 42, 不变, 因为 `copy` 是 `obj` 的拷贝

浅拷贝不会复制嵌套对象,如果obj包含一个对象属性nameObject.assign()会保持name原有的引用,而不是创建一个name的拷贝。

1
2
3
4
5
const obj = { name: { first: 'Jean-Luc', last: 'Picard' } };
const copy = Object.assign({}, obj);

copy.name.first = 'Johnny';
obj.name.first; // 'Johnny', `name` **没有** 克隆

一般来说,深拷贝对象需要类似lodash的库。另外也可以用JSON.stringify()序列化对象,然后用JSON.parse()解析成对象。

1
2
3
4
5
const obj = { name: { first: 'Jean-Luc', last: 'Picard' } };
const copy = JSON.parse(JSON.stringify(obj));

copy.name.first = 'Johnny';
obj.name.first; // 'Jean-Luc'

但是这种方法适用于只包含字符串、数值、布尔值、对象和数组的对象。例如,对象中有一个date属性是JavaScript的日期类型,拷贝对象的date属性会变成字符串,因为JSON.stringify()序列化日期会转换成字符串。

1
2
3
4
5
const obj = { date: new Date('2019-06-01') };
const copy = JSON.parse(JSON.stringify(obj));

obj.date instanceof Date; // true
copy.date instanceof Date; // false, `date` 是字符串