zoukankan      html  css  js  c++  java
  • JS对象的深浅拷贝及其新增方法测试

      我们在了解数据类型的时候,都知道一般的字符,数值,undefined和布尔值等都为一般数据类型,它们在进行数据传输的时候,进行的是值传递,当我们修改新数据,是不影响老数据的。但是我们今天要讲的是数据类型中的一种复杂数据,它的代表就是对象。

    // 一般数据的值拷贝
      // 将a的值作为实参传入函数执行函数语句,虽然函数体内的参数发生了改变
      // 却不会影响原数据的值
      var  a = 10 ;
      function fn(a){
          a = 20;
          console.log(a);   //20
      }
      fn(a);
      console.log(a);    //10

      对象的传递是一种引用传递,当发生数据的拷贝时,对象传递的是内存地址的指向,将两个变量的指向拉到同一个地址上去了,这就会导致当我们对新拷贝数据进行修改的时候,老数据也会受到影响,值也会发生改变,但这种改变是一定的么?那也不一定,这就引入了我们今天要测试的内容:对象的深浅拷贝。

      首先我们先来测试一下浅拷贝,浅拷贝简单来说就是对象只拷贝了地址,不拷贝值,这种情况就会导致我们上面所说的情况,具体代码测试如下:

     1 // 对象的浅拷贝:
     2   //声明对象并赋值
     3   var obj = {
     4       name:"admin"
     5   }
     6   // 创建函数进行拷贝
     7   function fn(obj2){
     8   // 执行语句将obj2的name值改为root        
     9       obj2.name = "root"
    10   }
    11   //执行函数并将obj的值传参给函数
    12   fn(obj);
    13   // 打印返回obj,此时obj的值发生了改变
    14   console.log(obj);            //{name:"root"}

      另一种就是我们今天要着重要介绍的深拷贝,与浅拷贝恰恰相反,深拷贝是只拷贝原对象的值,不拷贝地址,而这种拷贝模式就会让我们在处理对象数据拷贝问题时,可以在拷贝数据的同时不影响老数据。一般实现的方法如下: 

    // 对象的深拷贝
      // 一般我们利用for in对对象实现遍历达到深拷贝的目的
      var obj = {
          name :"admin"
      }
      // 声明空对象
      var obj2 = {};
      // 遍历老对象,赋值给新对象
      for(var i in obj){
      // 这里的赋值仅为值的拷贝,并没有拷贝地址
          obj2[i]=obj[i];
      }
      // 改变新对象的值
      obj2.name = "root";
      // 返回结果并未对老对象的值产生影响
      console.log(obj);                //{name:"admin"}
      console.log(obj2);            //{name:"root"}

      通过上面的测试我们可以得出for in的遍历可以实现对对象的深拷贝,但是它就是完美无缺的么?答案肯定是否定的,下面看一种特殊的对象拷贝情景,来测试for in 拷贝的特点:

    // 特殊对象的拷贝,测试for in的深拷贝特点
      var obj = {
          name:{
              name:"admin"
          }
      }
      var obj2 = {};
      // 遍历老对象,赋值给新对象
      for(var i in obj){
          obj2[i] = obj[i]
      }
      // 测试第一层值是否被深拷贝  (结果是成立的)
      // obj2.name = "root";
      // console.log(obj);                //{name:name:"admin"}
      // console.log(obj2);            //{name:"root"}
      // 测试第二层值是否被深拷贝 (结果是否定的)
      obj2.name.name = "root";
      console.log(obj);                //{name:name: "root"}
      console.log(obj2);            //{name:name: "root"}
      // 继续测试如果对象有两层以上的值时,for in就实现不了对对象的深拷贝。
      // 例 :var obj = {
      //     name:{
      //         name:{
      //             name:"admin"
      //         }
      //     }
      // }
      // 感兴趣的朋友可以自行测试
      // 由此引出for in遍历只能实现一层深拷贝的特点

      for  in只能实现一层深拷贝,那有什么方法是可以实现对对象完全的深拷贝呢?答案当然也是肯定的,在ES5中我们将会了解到JSON.parse(str)和JSON.stringify(obj)两种实现json/对象的序列化和反序列化的方法,这里我简单介绍一下,JSON.parse(str)是用来将json字符转化成对象的方法,而JSON.stringify(obj)则是将对象转化为json字符串的方法。利用这两种方法我们来实现对象深拷贝的另一种方法:

    // 特殊对象的拷贝,测试JSON.parse(str)和JSON.stringify(obj)的深拷贝
      var obj = {
          name:{
              name:"admin"
          }
      }
     var obj2 = JSON.parse(JSON.stringify(obj));
     // 利用JSON.stringify(obj)将obj对象转化为json,再将json通过JSON.parse()重新转化为一个新的对象赋值给obj2;
      // 测试第一层值是否被深拷贝  (结果是成立的)
      // obj2.name = "root";
      // console.log(obj);                //{name:name:"admin"}
      // console.log(obj2);            //{name:"root"}
      // 测试第二层值是否被深拷贝 (结果是成立的)
      obj2.name.name = "root";
      console.log(obj);                //{name:name: "admin"}
      console.log(obj2);            //{name:name: "root"}
      // 即使是三层测试结果同样是成立的
    由此可得对象完全深拷贝新黑科技。
  • 相关阅读:
    021.day21 反射 Class类 反射常用操作
    020.day20 线程概述 多线程优缺点 线程的创建 线程常用方法 生命周期 多线程同步
    019.day19 缓冲流 对象流 标准输入输出流
    018.day18 map集合如何实现排序 File类 IO流 字节流 字符流 编码
    017.day17 Map接口 克隆 treeSet集合排重缺陷
    016.day16 HashSet TreeSet 比较器Comparable Comparator
    015.day15
    014.day14
    013.day13
    线程
  • 原文地址:https://www.cnblogs.com/liguanlong/p/11431760.html
Copyright © 2011-2022 走看看