一、什么是浅拷贝

创建一个新对象,这个对象有着原始对象属性的一份精确拷贝。如果属性是基本类型,拷贝的就是基本类型的值,如果属性是引用类型,拷贝的就是引用类型的指针。如果原对象改变了这个指针,拷贝对象也会受影响。
将B对象拷贝到A对象中,但不包括B对象里面的子对象。浅拷贝只是复制一层对象的属性,并不包括对象里面的引用类型的数据。
JavaScript-手写优秀的拷贝 - 图1

二、实现浅拷贝的方法:

1.Object.assign()
2.扩展运算符(…)
3.Array.prototype.slice() && Array.prototype.concat()

三、什么是深拷贝

将一个对象内存中完全拷贝出来,分配一个新的内存区域存放新的对象,且修改对象不会影响到原来的对象
将对象B拷贝到A对象中,包括B里面的子对象。它不仅将原对象的各个属性逐个复制出去,而且将原对象各个属性所包含的对象也依次采用深复制的方法递归复制到新对象上。
JavaScript-手写优秀的拷贝 - 图2

四、如何实现深拷贝

4.1 JSON.parse(JSON.stringify(xxxx))
~优点:简单易使用
~缺点:会忽略undefined、symbol。不能序列化函数。不能解决循环引用问题
4.2 消息通道messageChannel
~优点:能解决undefined和循环应用的问题
~缺点:是一个异步函数

  1. function clone(obj) {
  2. return new Promise(resolve => {
  3. const {port1, port2} = new MessageChannel();
  4. port2.onmessage = ev => resolve(ev.data);
  5. port1.postMessage(obj);
  6. });
  7. }

4.3 递归函数
~优点:能解决undefined、Symbol和函数的问题
~缺点:不能循环引用

  1. function deepClone(target) {
  2. function isObj(o) {
  3. return (typeof o === 'object' || typeof o === 'function') && o !== null
  4. }
  5. if(isObj(target)) {
  6. let cloneTarget = Array.isArray(target)?[]:{}
  7. for(const key in target) {
  8. cloneTarget[key] = deepClone(target[key])
  9. }
  10. return cloneTarget
  11. } else {
  12. return target
  13. }
  14. }

4.4 优化递归函数
~优点:能解决undefined、Symbol、函数的问题和循环引用问题。
~缺点:存在一定的性能问题。

  1. function deepClone(target, map = new Map()) {
  2. function isObj(o) {
  3. return (typeof o === 'object' || typeof o === 'function') && o !== null
  4. }
  5. if(isObj(target)) {
  6. let cloneTarget =Array.isArray(target) ? [] : {}
  7. if(map.get(target)) {
  8. return map.get(target)
  9. }
  10. map.set(target, cloneTarget)
  11. // 这里可以使用while来提高性能
  12. for(const key in target) {
  13. cloneTarget[key] = deepClone(target[key], map)
  14. }
  15. return cloneTarget
  16. } else {
  17. return target
  18. }
  19. }