# 深浅拷贝

浅拷贝和深拷贝都是对于 JS 中的引用类型而言的,浅拷贝就只是复制对象的引用,如果拷贝后的对象发生变化,原对象也会发生变化。只有深拷贝才是真正地对对象的拷贝。

  • 基本类型 Number,String,Boolean,Null,Undefined ,Symbol
  • 引用类型 Object 类型、Array 类型、Date 类型、RegExp 类型、Function 类型 等

# 浅拷贝

只会将对象的各个属性进行依次复制,并不会进行递归复制,也就是说只会赋值目标对象的第一层属性

# 实现方式

  1. Array.concat()
  2. Object.assign()
  3. arr.slice()
  4. [...array]
  5. 函数库 lodash 的_.clone方法

# 深拷贝

# 实现方式

# 一 、JSON.parse()和 JSON.stringify()

缺点

  1. undefined、任意的函数、正则表达式类型以及 symbol 值,在序列化过程中会被忽略(出现在非数组对象的属性值中时)或者被转换成 null(出现在数组中时)
  2. 它会抛弃对象的 constructor。也就是深拷贝之后,不管这个对象原来的构造函数是什么,在深拷贝之后都会变成 Object
  3. 如果对象中存在循环引用的情况无法正确处理

# 二、函数库 lodash 的_.cloneDeep方法

lodash.cloneDeep 源码 (opens new window)

# 三、jQuery.extend()方法

# 四、手写递归函数

var deepCopy = function (obj, map = new WeakMap()) {
  // 基本类型
  if (typeof obj !== 'object') {
    return obj
  }
  // 数组和对象的处理
  const newObj = obj instanceof Array ? [] : {}
  // 循环引用的问题
  if (map.has(obj)) {
    return map.get(obj)
  }
  map.set(obj, newObj)

  for (let key in obj) {
    newObj[key] = deepCopy(obj[key], map)
  }
  return newObj
}
const a = { a: 1, b: [1, 2, 3], c: { a: { c: 1 } } }
const b = deepCopy(a)
a.c === b.c
// 循环引用测试用例
const target = {
  field1: 1,
  field2: undefined,
  field3: {
    child: 'child',
  },
  field4: [2, 4, 8],
}
target.target = target
const d = deepCopy(target)

# 循环引用的处理

# 参考文章

浅拷贝与深拷贝 (opens new window)

JavaScript 专题之深浅拷贝 (opens new window)

如何写出一个惊艳面试官的深拷贝? (opens new window)