• 谈谈深浅拷贝的问题(1)


    这里先来整理一下对象的拷贝 
    我们都知道,对象是个复杂类型,这个变量就只是个指针。举个例子

    var a=new String("abc")
    var b=new String("abc")
    console.log(a==b) //false

    变量a和变量b是不相等的,因为他们指向的不是同一个对象。

    console.log({}=={}) //false
    console.log({a:1}=={a:1}) //false

    对象的复制操作呢?可以直接变量赋值么?

    var a={age:18}
    var b=a
    console.log(b) // {age:18}
    console.log(a==b) //true

    注意看,这里是不是很奇怪,刚刚我们操作console.log({a:1}=={a:1})结果是false 现在 console.log(a==b),结果居然是true.

    这说明什么?这表示变量a和变量b指向的都是同一个内存地址,就是存放{a:1}的地址。

    b.age=20
    console.log(b.age) //20
    console.log(a.age) //20

    当我们改变了b.age的值之后,果然a.age的值也发生了变化。很明显,这样子的拷贝方式不能接受

    直接复制不可取,那换一种方式呢?我们定义一个函数,循环的遍历一下。

    function copy(obj){
      var res={}
      for(var i in obj){
        if(obj.hasOwnProperty(i)){
          res[i]=obj[i]
        }
      }
      return res
    }
    var obj1={age:18}
    var obj2=copy(obj1)
    console.log(obj2) //{age:18}

    我们对这个返回的新数操作一下,看看结果如何

    obj2.age=20
    console.log(obj1.age) //18
    console.log(obj2.age) //20

    这样子看起来,改变了obj2的 a 属性的值,obj1的 a 的的属性的值没有变化,这样子是不是就可以了呢?
    我们把这个obj1数组再变化一下。

    obj1 = {
      age: 18,
      position: ["北京", "广州", "上海"],
      name: {
      first: "lily",
      last: "lucy"
      }
    }

    此时的onj1不再是一个简单的对象了,他的属性有的是数组,有的是对象 。再操作一下

    obj2.position[0]="深圳"
    console.log(obj1.position)      //["深圳","广州","上海"]
    console.log(obj2.position)      //["深圳","广州","上海"]

    我们改变了obj2的 position[0]的值,把 “北京” 变成了 “深圳” ,结果,obj1和obj2都发生了改变。 
    那么问题来了,为什么改变 age 和改变 position 的结果是不一样呢?来看看对象obj1

    var obj1 = {
      age: 18,
      position: ["北京", "广州", "上海"],
      name: {
        first: "lily",
        last: "lucy"
      }
    }

    当我们循环遍历对象a的属性。分开来分析

    第一步,遍历属性age,把这个age赋值到obj2对象中去, 由于age就是个基本类型的变量,值为18,这就相当于 var a=18 b=a,因此obj2中的age保存的就是18

       这里要和 var a={age:18} b=a 区别开来,这里的赋值是b=a, 是把 a赋值给b这是一个引用 ,而上面是把 obj1 的属性age 赋值给 obj2的属性age,这个age就是一个基本类型18

    你要分清楚,赋过去的值,到底是一个基本类型还是一个引用

    第二步 ,把obj1的position属性赋值给obj2,position指向的是一个数组,也就是说,传递给obj2的position和obj1的position指向的都是同一个地址.

    同理,当我们赋值name属性的时候,这个属性是对一个对象的引用,也是一个指针。

     我们来尝试改进一下,把 position 和  name:这两个引用属性,再调用这个函数操作,可否?

     function find(copy,orig) {
        var copy=copy||{}
        for (var i in orig) {
          if (typeof orig[i] === 'object') {
              copy[i] = orig[i].constructor === Array ? [] : {}
              find(copy[i],orig[i])
           }else{
                copy[i]=orig[i]
             }
        }
     }
     var obj1 = {
         age: 18,
         position: ["北京", "广州", "上海"],
         name: {
              first: "lily",
              last: "lucy"
         }
     }
     var obj2={sex:"girl"}
     find(obj2,obj1)

    再来测试一下,看看这个函数能否满足深复制的要求

      obj2.name.first="mark" 
      console.log(obj1.name)   //{first: "lily", last: "lucy"}
      console.log(obj2.name)   //{first: "mark", last: "lucy"}

    obj2.position[0]="海南"
    console.log(obj1.position)   //["北京", "广州", "上海"]
    console.log(obj2.position)   //["海南", "广州", "上海"]

    可以看到,这样子复制是完成了的.我们再来测试一下。多包裹几层,看看是否可以

    var obj1 = {
          age: 18,
          position: ["北京", "广州", "上海"],
          name: {
              first:{
                  a:1,
                  b:2
              },
              last: "lucy"
          }
      }
      var obj2={sex:"girl"}
      find(obj2,obj1)
      obj2.name.first.a=7
      console.log(obj1.name.first)   //{a: 1, b: 2}
      console.log(obj2.name.first)   //{a: 7, b: 2}

    由于是递归的调用了这个拷贝函数,无论你的对象嵌套的层次有多么的深,总是可以保证拷贝成功的。

    这里还有一个问题需要注意的,放到下一章节,点击这里查看下一章节

  • 相关阅读:
    centos 安装 py 3.0+
    ubuntu下安装多版本Python
    DRF之注册器响应器分页器
    头部随着滚动高度的变化由透明慢慢变成不透明
    悬浮滚动
    判断某天是周几
    正则限制input只能输入大于0的数字
    原生js倒计时
    从两个时间段里分别计算出有几天工作日与周末
    sublime text3连续打出1到10的标签div
  • 原文地址:https://www.cnblogs.com/yiyistar/p/7461256.html
Copyright © 2020-2023  润新知