深拷贝&&浅拷贝

浅拷贝和深拷贝的几种常见方法

浅拷贝

复杂类型即对象在赋值过程中其实复制的是一个地址(指针),这个指针指向计算机的一小块内存,从而导致修改一个地方其他地方也跟着改变,但我们不希望这种情况发生,可以使用浅拷贝解决这个问题

1
2
3
4
5
6
let a = {
age: 18
}
let b = a;
a.age = 20;
console.log(b.age); // 输出20

  • 通过Object.assign,它只会拷贝所有的属性值到新对象中,如果属性值是对象的话,拷贝的是地址,并不是深拷贝

    1
    2
    3
    4
    5
    6
    let a = {
    age: 18
    }
    let b = Object.assign({},a);
    a.age = 20;
    console.log(b.age); // 18
  • 另外还可以通过展开运算符…来实现浅拷贝

    1
    2
    3
    4
    5
    6
    let a = {
    age: 18
    }
    let b = { ...a }
    a.age = 20
    console.log(b.age) // 18

浅拷贝只解决了第一层问题,如果接下去的值中还有对象的话,那么就又回到最开始的话题了,两者享有同一个地址。要解决这个问题,我们就要使用深拷贝了

深拷贝

  • JSON实现深拷贝
    1
    2
    3
    4
    5
    6
    7
    8
    9
    let a = {
    age: 18,
    jobs: {
    first: 'doctor'
    }
    }
    let b = JSON.parse(JSON.stringify(a)) // 将这个对象变成字符串,再从这个字符串中生成一个对象
    a.jobs.first = 'teacher'
    console.log(b.jobs.first) // doctor

但是这个方法有局限性,JSON不支持函数,引用,undefined,正则,Date日期对象

  • 如果想自己实现一个深拷贝,这里只能实现一个简易版本,有许多边界情况没有考虑到,但在实际应用中更推荐lodash的深拷贝函数https://lodash.com/docs/4.17.11#cloneDeep
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    function deepClone(obj) {
    function isObject(o) {
    return (typeof o === 'object' || typeof o === 'function') && o !== null
    }

    if (!isObject(obj)) {
    throw new Error('非对象')
    }

    let isArray = Array.isArray(obj)
    let newObj = isArray ? [...obj] : { ...obj }
    Reflect.ownKeys(newObj).forEach(key => {
    newObj[key] = isObject(obj[key]) ? deepClone(obj[key]) : obj[key]
    })

    return newObj
    }

    let obj = {
    a: [1, 2, 3],
    b: {
    c: 2,
    d: 3
    }
    }
    let newObj = deepClone(obj)
    newObj.b.c = 1
    console.log(obj.b.c) // 2
0%