javascript 中赋值,浅拷贝,深拷贝的区别与源码解析

134 阅读2分钟

本文讲述一下赋值,浅拷贝和深拷贝的区别和原理解析。

    var person = {
      name:'小周',
      hobby:['游泳',['学习','画画']]
    }
    //赋值就是创建一个变量来指向原本的person对象,其本质是创建一个变量(此处指的是person1)同时指向person对象一样内存地址的堆。
    var person1 = person
    person1.name = '小许'
    person1.hobby[0] = '敲代码'
    console.log(person.name,person1.hobby[0]) //输出 小许 敲代码
    console.log(person1.name,person1.hobby[0])//输出 小许 敲代码

由此可见,输出一致,说明无论是基本类型数据还是引用类型数据,同一内存地址下的两个指针,有一个改变内存中的属性,另一指针也会受到影响

    var person = {
      name:'小周',
      hobby:['游泳',['学习','画画']]
    }
    function shallowCopy(obj){
      var person1 = {}
      //开始遍历obj里的每一个属性
      for(var i in obj){
        //判断obj第一层(无引用数据类型嵌套的一层)
        if(obj.hasOwnProperty(i)){
          //此处把简单地复制第一层,没有针对里面嵌套引用数据类型进行操作
          person1[i] = obj[i]
        }
      }
      return person1
    }

    var Obj = shallowCopy(person)
    Obj.name = "小许"
    Obj.hobby[0] = "敲代码"
    console.log(person.name,person.hobby[0]) //输出 小周 敲代码
    console.log(Obj.name,Obj.hobby[0])//输出 小许 敲代码
     

由此可见,在浅拷贝中,原对象(person)与拷贝对象(Obj)的基本数据类型已经不存在相互影响,而引用数据类型依旧是“一改全改” 说明浅拷贝只是半拷贝,在内存中创建一个新的对象空间,拷贝完后基本数据类型独立存在,而嵌套在新的对象存储空间的内部引用数据类型依旧是与原对象里的引用数据类型指向同一个地址,故依旧是相互影响。

    var person = {
      name:'小周',
      hobby:['游泳',['学习','画画']]
    }
    function deepCopy(obj){
      var person1 = {}
      //判断递归的边界,当传进来的obj的类型不再是引用数据类型时,停止继续递归调用并开始返回
      if(typeof obj !== 'object'){
        return obj
      }
      for(var i in obj){
        if(obj.hasOwnProperty(i)){
          //第一层进入后,递归再进入判断是否嵌套着引用数据类型。
          person1[i] = deepCopy(obj[i])
        }
      }
      return person1
    }
    var Obj = deepCopy(person)
    Obj.name = "小许"
    Obj.hobby[0] = "敲代码"
    Obj.hobby[1][0] = '睡觉'
    console.log(person.name,person.hobby[0],person.hobby[1][0])//输出  小周 游泳 学习
    console.log(Obj.name,Obj.hobby[0],Obj.hobby[1][0])//输出  小许 敲代码 睡觉

在深度拷贝的情况下,新的变量创建新的存储地址,将原数据拷贝一份给新的对象,新的对象与原数据任一数据进行修改,基本数据类型和引用数据类型之间互不影响。 属于完全拷贝,两份数据完全“独立”。