【工具方法】deepClone

4/1/2021 面试编程能力

# 参考资料

WeakMap (opens new window)

# 实现原理

  • 值类型及 Date、RegExp 拷贝完可以终止
  • weakMap解决循环引用
  • 递归拷贝 Array 和 Object 属性

# 代码实现

/**
 * 深拷贝
 * @param {any} origin 被克隆者
 */
const myDeepClone = function (origin, wm = new WeakMap()) {
  // 处理一般对象
  if (typeof origin !== 'object' || origin == null) return origin
  if (origin instanceof Date) return new Date(origin)
  if (origin instanceof RegExp) return new RegExp(origin)
  // weakMap 处理循环引用
  const stashed = wm.get(origin)
  if (stashed) return stashed
  let target = Array.isArray(origin) ? [] : {}
  wm.set(origin, target)
  // 递归拷贝每个属性(Array or Object)
  for (let key in origin) {
    if (origin.hasOwnProperty(key)) {
      target[key] = myDeepClone(origin[key], wm)
    }
  }
  return target
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

# 测试一下

一般对象

var p1 = {
  name: 'william',
  age: 12,
  birthday: new Date('1995-09-12'),
  hobby: ['eat', 'sleep', 'code'],
  address: {
    city: 'shenzhen'
  },
}

var p2 = myDeepClone(p1)
p1.address.city = 'beijing'
p2.hobby.push('music')
console.log(p1, p2) // p1、p2 相互独立
1
2
3
4
5
6
7
8
9
10
11
12
13
14

循环引用的对象

var o1 = {x: 1}, o2 = {y: 2}
o1.a = o2
o2.b = o1
var o3 = myDeepClone(o1)
o1.z = 100
console.log(o1, o3)
1
2
3
4
5
6

循环引用的数组

var arr1 = [1, 2, 3]
arr1.push(arr1)
var arr2 = myDeepClone(arr1)
arr2.push(1)
console.log(arr1, arr2)
1
2
3
4
5
Last Updated: 4/8/2021, 12:53:45 PM