• 深拷贝与浅拷贝


    引子

    什么是浅拷贝?什么是深拷贝?浅显易懂的说:假设B复制了A,如果B发生变化,A也随之变化,那么说明为浅拷贝;若B发生变化,并不会导致A也发生变化,则称之为深拷贝。

    举个例子:

    let a = [0,1,2]
    let b = a
    b[0] = 1
    console.log(a,b)

     

    不禁疑惑,数组b复制了数组a,明明只修改了数组b,为什么数组a也随着改变呢?

    此时需要引入基本数据类型和引用数据类型的概念


    基本数据和引用数据

    基本数据类型有哪些?

    null,undefined,number,string,boolean,symbol

    引用数据类型?

    有常规名值对的无序对象{a:1},还有数组[1,2,3]和以及函数

    有了解过基本数据类型和引用数据类型的存储方式吗?
    • 基本数据类型的变量名和值都存储在栈内存中

      //当执行了直接赋值时
      let a = 1
      let b = a//在栈内存中开辟了新的内存来保存名与值
      b = 2
      console.log(a,b)//1,2
      栈内存  
      name val
      a 1
      b 1


       

    • 引用数据类型的变量名存放在栈内存中,但是值却存放在堆内存中,栈内存会提供一个引用地址指向堆内存中的值

      let a = [0,1]
      let b = a
      b[0] = 1
      console.log(a,b)//1,1   1,1

      分析:复制时,只拷贝了引用地址,而并非堆内存中的值

      修改时,由于a和b同时指向了同一个引用,因此两者会互相影响,也就是所谓的浅拷贝了

      栈内存 堆内存
      name val  
      a 引用地址 [1,1]
      b 引用地址 [1,1]

      不禁发出疑问:假如拷贝时,在堆内存中也能开辟新的内存来专门存放b的值,如同基本数据类型在栈内存中的表现一样,应该便能实现深拷贝了。


    实现深拷贝

    递归实现深拷贝
    //只适用于对象和数组的深拷贝
    function deepclone(targetObj){
        let cloneObj = Array.isArray(targetObj) ? [] : {}
        //如果目标对象为引用类型
        if(targetObj && typeof targetObj === 'object') {
            for(let key in targetObj){
                //判断目标对象的属性是否也是引用类型,
                if(targetObj[key] && typeof targetObj[key] === 'object'){
                    cloneObj[key] = deepclone(targetObj[key])
                }else {
                    //如果是基本类型,那么可以直接赋值复制
                    cloneObj[key] = targetObj[key]
                }
            }
        }
        return cloneObj
    }
    let arr = [0,1,2,[0,1]]
    let copy = deepclone(arr)
    copy[0] = 1
    copy[3][0] = 1
    console.log(arr,copy)

        
    借用JSON对象的parse和stringify
    function deepClone(obj){
        let _obj = JSON.stringify(obj)
        let cloneObj = JSON.parse(_obj)
        return cloneObj
    }
    let obj = {name:'mike',age:16,son:{name:'tom'}}
    let copy = deepClone(obj)
    copy['name'] = 'john'
    copy.son.name = 'Tom'
    console.log(obj,copy)

    某些API所实现的深浅拷贝

    Array.prototype.concat()实现数组的不完全深拷贝
    let arr = [0,1,2,[1,2]]
    let copy = arr.concat()
    copy[0] = 1
    copy[3][0] = 2
    console.log(arr,copy)

    Array.prototype.slice()实现数组不完全深拷贝

    只能实现第一层属性的深拷贝,原因在于,方法返回一个新的数组对象

    let a=[0,1,[2,3],4],
            b=a.slice();
    a[0]=1;
    a[2][0]=1;
    console.log(a,b);

    Object.assign()实现的不完全深拷贝
    let obj = {name:'mike',son:{name:'son'}}
    let copy = Object.assign({}, obj)//因为方法返回目标对象{},实现了第一层的深拷贝
    copy['name'] = 'john'
    copy.son.name = 'Son'//第二层为浅拷贝了,所以修改copy对象时,obj对象的第二层也改变了
    console.log(obj,copy)

    深拷贝的实用性

    后台返回一堆数据时,在多人开发中,我们不知道数据是否有其他的开发需求,因此我们不能直接修改数据,深拷贝可以使我们安心操作拷贝的数据,而无需担心修改原数据带来的隐性问题。

     

  • 相关阅读:
    获取网卡信息
    MVC Razor
    MVC
    Windows 消息
    sql 总结
    学生成绩表 SQL练习题
    oracle与sqlserver的十大区别
    for的冒泡排序练习题
    对于for的一些认识
    穷举
  • 原文地址:https://www.cnblogs.com/joeynkay/p/13461356.html
Copyright © 2020-2023  润新知