什么是浅拷贝?

浅拷贝只是复制了对象的引用地址,两个对象指向同一个引用地址,修改其中任意的值,另一个值都会随之变化,这就是浅拷贝。

如何实现浅拷贝?

使用Object.assign()来解决浅拷贝,Object.assign()只会拷贝所有的属性值到新的对象中,如果属性值是对象的话,拷贝的是对象的地址,所以并不是深拷贝,而是浅拷贝。

下面来看一个例子:

  1. let obj1 = {a:1};
  2. let obj2 = Object.assign({},obj1);
  3. obj2.a = 2
  4. console.log(obj1.a) // 1

很明显对象obj2是通过obj1拷贝出来的,我们将obj2.a = 2,此时obj1.a仍然是1,我们通过Object.assign()实现了拷贝。

同时展开运算符…也可以实现浅拷贝,示例如下:

  1. let a = {age:1};
  2. let b = {...a};
  3. b.age = 2
  4. console.log(a.age) // 1

但是下面这个示例我们使用浅拷贝就有点困难了,

  1. let a = {
  2. name:'zwj',
  3. age: {first:1}
  4. }
  5. let b = Object({},a)
  6. b.age.first = 3;
  7. console.log(a.age.first) // 3

很显然对象a的属性age的值为一个对象,这样就不能完全拷贝了。因为浅拷贝只能解决对象第一层的拷贝,如果第二层及接下去的层级为对象的情况时,只是拷贝了对象的地址,这时我们就得考虑深拷贝了。

什么是深拷贝?

深拷贝是将对象及其值复制过来,两个对象修改其中任意的值另一个对象都不会改变,这就是深拷贝。

如何实现深拷贝?

我们通常使用JSON.parse(JSON.stringify(obj))来解决。让我们在来看一下上面的例子:

  1. let a = {
  2. name:'zwj',
  3. age: {first:1}
  4. }
  5. let b = JSON.parse(JSON.stringify(a))
  6. b.age.first = 3;
  7. console.log(a.age.first) // 1

可以看到通过上面的a.age.first = 1,通过JSON.parse(JSON.stringify())成功的将对象深拷贝了。

下面再让我们看一个例子,让对象a做一下改变

  1. let a = {
  2. name: 'zwj',
  3. age: undefined,
  4. sex: Symbol('male'),
  5. jobs: function(){}
  6. }
  7. let b = JSON.parse(JSON.stringify(a))
  8. console.log(b) // {name: 'zwj'}

你会发现通过JSON.parse(JSON.stringify(a))出来的b只有name一个属性了,其余的哪去了呢?所以JSON.parse(JSON.stringify())也是有缺陷的,它并不是万能的,此方法有下面几个缺陷:

  • 会忽略 undefined
  • 会忽略 Symbol
  • 不能序列化函数

如果我们想要一个可以实现完全深拷贝的函数,我们可以使用lodash库中的_.cloneDeep(),此方法会实现一个深拷贝,或者我们简单的来写一个深拷贝的函数

  1. function cloneDeep(obj){
  2. function isObject(o){
  3. return (typeof o === 'object' || typeof o === 'function') && o !== null
  4. }
  5. if(!isObject(obj)){
  6. throw new Error('非对象')
  7. }
  8. let isArray = Array.isArray(obj);
  9. let newObj = isArray ? [...obj] : {...obj};
  10. Reflect.ownKeys(obj).forEach(key => {
  11. newObj[key] = isObject(obj[key]) ? cloneDeep(obj[key]) : obj[key]
  12. })
  13. return newObj
  14. }
  15. let obj = {
  16. a: [1,2,3],
  17. b: {
  18. c: 2,
  19. d: 3
  20. }
  21. }
  22. let newObj = cloneDeep(obj)
  23. newObj.b.c = 1
  24. console.log(obj.b.c) // 2

总结

拷贝:其实就是一个对象复制给另外一整个对象,让对象相互不影响
对象的拷贝又分为浅拷贝和深拷贝:对象的浅拷贝(只拷贝一层)、 对象的深拷贝(拷贝多层)
浅拷贝和深拷贝只针对object和Array这样的复杂的对象

所谓的浅拷贝,只是拷贝了基本类型的数据,对于引用的类型数据,复制后也是会发生引用,这种拷贝就叫做浅拷贝

而深拷贝,要求要复制一个复杂的对象,这就可以利用递归的思想来实现,省性能又不会发生引用,它不仅将原对象的各个属性逐个复制出去,而且将原对象各个属性所包含的对象也依次采用深复制的方法递归复制到新对象上