美文网首页
JS中的浅拷贝与深拷贝

JS中的浅拷贝与深拷贝

作者: 西洲何在 | 来源:发表于2018-04-24 17:38 被阅读0次

    前言

    近来浏览一篇关于JavaScript的数据引用类型的浅拷贝和深拷贝的文章,感觉作者讲的浅显易懂,解决我一直以来不太理解深拷贝和浅拷贝的问题,所以要记录下来,以免以后忘记。

    文前案例

    let num1 = 1, num2 = num1
    
    num2 = 2
    
    console.log(num1) // 1
    console.log(num2) // 2
    
    let obj1 = {name: 'Tom', age: 19}, obj2 = obj1
    
    obj2.age = 23
    
    console.log(obj1 ) // {name: 'Tom', age: 23}
    console.log(obj12) // {name: 'Tom', age: 23}
    

    看到这个案例,可能会有点懵,这和拷贝有什么关系?且听我说来,从第一个例子看来,当改变num2时,num1并没有改变,按照常规想法,obj1.age应该不会随着obj2.age的改变而改变的,但实际并非如此,这是因为数据类型的差别,在JavaScript中数据主要分为两种类型,基本类型和引用类型,基本类型主要有Number,String,Null,Undefined,Boolean等,引用类型Array,Object等,基本类型在内存中的储存和引用类型是不一样的,引用类型的变量名实际是指向一个内存地址名,非实际的内存,所以当引用类型的copy赋值时,实际赋值的是内存地址名。而此时的obj1和obj2指向的是同一个内存地址,当修改其中一个时,会修改内存地址中的数据,从而导致另一个改变。这就是浅拷贝,只是拷贝了引用的地址名,所以深拷贝与浅拷贝的概念只是存在于引用类型中。

    深拷贝与浅拷贝

    看到的那篇文章用了一个很形象的日常例子来说明深拷贝和浅拷贝的区别,连锁店和普通店,深拷贝就像连锁店,每个店都是深度拷贝,其中一个店货物改变,并不影响其他店,而浅拷贝就像普通店的钥匙,可以分给不同店长,他们改变货物,就会影响整个店的货物。

    浅拷贝其实不是我们要研究的,我们往往是希望深拷贝,因为在实际应用中,我们是不希望在修改拷贝的时候,影响父本的数据,现在我们只说说Array和Object怎么样深拷贝。

    Array的深拷贝

    在JS里内置了很多操作数组的方法,那么有没有可以深拷贝的方法呢?是有的。

    let arr = [1,2,3]
    let arr1 = arr.slice()
    arr1[0] = 4
    
    console.log(arr) // [1,2,3]
    console.log(arr1)  // [4,2,3]
    
    let arr2 = [1,2,3,[4,5]]
    let arr3 = arr2.slice()
    
    arr3[3][0] = 6
    
    console.log(arr2) // [1,2,3,[6,5]]
    console.log(arr3)  // [1,2,3,[6,5]]
    

    从例子上我们可以看出,slice()方法的确可以深度拷贝,但只适用于一维数组的深拷贝,类似的concat()方法也是如此,那么如何实现多维数组的深拷贝呢?递归是一个好方法,且看我写来。

    function deepArray(arr) {
      let result = []
      let temp = null
    
      arr.forEach((val, index) => {
        temp = val
        if (temp && temp instanceof Array) {
          result[index] = deepArray(temp)
        } else {
          result[index] = temp
        }
      })
      return result
    }
    
    let arr4 = [1,2,3,[4,5]]
    let arr5 = deepArray(arr4)
    
    arr5[3][0] = 6
    
    console.log(arr2) // [1,2,3,[4,5]]
    console.log(arr3)  // [1,2,3,[6,5]]
    

    object的深拷贝

    既然在array里有深拷贝的方法,那么在object里也是有的,在es6的标准下,新加入的方法,Object.assign(),这是合并对象的一个方法,但是它也只是能够深拷贝一维的对象,这里我们依然可以使用递归的方法完成对象的多维深拷贝

    function deepCopy(obj) {
        let result = {}
        let keys = Object.keys(obj)
        let temp = null
        let key = null
        for (let i = 0; i < keys.length; i++) {
            key = keys[i]
            temp = obj[key]
            if (temp && typeof temp === 'object') {
                result[key] = deepCopy(temp)
            } else {
                result[key] = temp
            }
        }
        return result
    }
    
    var obj1 = {
        x: {
            m: 1
        },
        name: 'tom'
    }
    var obj2 = deepCopy(obj1)
    obj2.x.m = 2
    console.log(obj1) // {x: {m: 1}, name: 'tom'}
    console.log(obj2) // {x: {m: 2}, name: 'tom'}
    

    相关文章

      网友评论

          本文标题:JS中的浅拷贝与深拷贝

          本文链接:https://www.haomeiwen.com/subject/ufmllftx.html