美文网首页
js-引用类型对象拷贝

js-引用类型对象拷贝

作者: 好奇而已 | 来源:发表于2017-04-18 15:15 被阅读405次

    1.引用类型; 2.过滤数组; 3.深浅拷贝方法;

    1.引用类型有哪些?非引用类型有哪些

    • 引用类型:
      引用类型(Object, Array, Function, Date, Math, RegExp, Error)指的是那些保存在堆内存中的对象,变量中保存的实际上只是一个指针,这个指针指向内存中的另一个位置,由该位置保存对象。

    • 非引用类型(基本数据类型):
      number,string,boolean,undefined, null.
      指的是保存在栈内存中的简单数据段.

    • 基本类型 == 非引用类型
      复杂类型 == 对象 == 引用类型

    2.如下代码输出什么?为什么

    var obj1 = {a:1, b:2};
    var obj2 = {a:1, b:2};
    console.log(obj1 == obj2);//输出:fasle:会比较两者内存地址,发现内存地址不一样.
    
    console.log(obj1 = obj2);// 输出 : Object {a: 1,b: 2}
    :这一步把obj2的内存地址给了obj1,从此两者共用一份内存地址.
    
    console.log(obj1 == obj2);//输出:ture :因为两者共用一份内存地址了
    
    

    3.如下代码输出什么? 为什么

    var a = 1;
    var b = 2;
    var c = { name: '饥人谷', age: 2 };
    var d = [a, b, c];
    
    var aa = a;//a=1
    var bb = b;//a=2
    var cc = c;
    var dd = d;
    
    a = 11;//aa=1:基本类型引用,只会让a=11,aa和a 是指向两块不同的内存空间(即指针).不干扰
    b = 22;//bb=2
    c.name = 'hello';//{name: "hello", age: 2}
    d[2]['age'] = 3;//这句把c对象字面量改为{name: "hello", age: 3}
    
    console.log(aa); //1 
    console.log(bb);//2
    console.log(cc);//Object{name: "hello", age: 3}  :引用类型中:两个变量指向同一个堆对象,改变其中一个变量,另一个也会受到影响
    console.log(dd);//[1,2,Object{age: 3, name: "hello"}]
    
    
    
    

    4.如下代码输出什么? 为什么

    var a = 1;
    var c = { name: 'jirengu', age: 2 };
    
    function f1(n){
      //var n =a;相当于有这步,但并没有给a开辟新的内存.
      ++n;
    }
    function f2(obj){
      ++obj.age;
    }
    
    f1(a);//a=1  n=2
    f2(c);//c={name: 'jirengu', age: 2 };
    f1(c.age);//c={name: 'jirengu', age: 3 };对象a的点语法访问的是同一个内存地址,所以原指针c的age属性会改变.
    console.log(a);//a=1
    console.log(c);//Object {name: 'jirengu', age: 3 };
    
    

    5.过滤如下数组,只保留正数,直接在原数组上操作

     var arr = [3,1,0,-1,-3,2,-5];
      
      function filter(arr){
    
        for(var i=0;i<arr.length;i++){
          if( arr[i]<1 ) {
            arr.splice(i,1); //splice(i,1)会从第i个开始,删除1个数,用于数组增删元素
            --i;  //当删除一个元素,arr的长度会减1,但for循环的i会一直加1,这样每次删一个,会漏掉被删元素后一个的元素的判断
          }
     
        }
    
      }
      filter(arr);
      console.log(arr); // [3,1,2]
    

    6.过滤如下数组,只保留正数,原数组不变,生成新数组

    方法1:

     var arr = [3,1,0,-1,-3,2,-5];
        function filter(arr){
          var newarr = [];
          for(var i = 0;i<arr.length;i++ ){
             if(arr[i]>0 ){
               newarr.splice(i,0,arr[i]);//splice第二个参数如果设置为 0,则不会删除项目,第三个参数是添加的参数.
             }
          }
          return newarr;
        }
        var arr2 = filter(arr);
        console.log(arr2); // [3,1,2]
        console.log(arr);  // [3,1,0,-1,-2,2,-5]
    

    方法2:

    var arr = [3,1,0,-1,-3,2,-5];
    function filter(arr){
        var newArr = [];
        for(var i = 0; i<arr.length;i++){
            if(arr[i]>0){
                newArr.push(arr[i]);
            }
        }
        return newArr;
    }
    var arr1 = filter(arr);
    console.log(arr1);
    console.log(arr);
    

    方法3:

    var arr = [3,1,0,-1,-3,2,-5];
    function filter(arr){
      var j = 0;
      var newarr = [];
      for( var i = 0; i < arr.length; i++){
        if( arr[i] > 0){
          newarr[j] = arr[i];
          j++;
        }
      }
      return newarr;
    }
    var arr2 = filter(arr);
    console.log(arr2); // [3,1,2]
    console.log(arr);  // [3,1,0,-1,-2,2,-5]
    

    7.写一个深拷贝函数,用两种方式实现

    • 在JavaScript中,对于Object和Array这类引用类型值,当从一个变量向另一个变量复制引用类型值时,这个值的副本其实是一个指针,两个变量指向同一个堆对象,改变其中一个变量,另一个也会受到影响

    • 而引用类型拷贝分为两种
      浅拷贝:拷贝原对象的引用.
      深拷贝:是拷贝出一个新的实例,新的实例和之前的实例互不影响.两份不同的内存地址.

    • 方法一

    function deepCope(obj){
        var newObj = {}; 
        for(var key in obj){
         //只赋值对象自己的属性,原型上的属性不赋值
          if(obj.hasOwnProperty(key)){//obj.hasOwnProperty(prop)这个方法可以用来检测一个对象是否含有特定的自身属性
            if(typeof obj[key] ==== 'number' ||
               typeof obj[key] ==== 'string' ||
               typeof obj[key] ==== 'undefined' ||
               typeof obj[key] ==== 'boolean' ||
                      obj[key] ==== null){//由于typeof null返回值也是object,所以不能直接用typeof obj[key] === 'object'来判断
             newObj[key] = obj[key];
            }else{
              newObj[key] = deepCope(obj[key]);//递归
          }
            
        }
          return newObj;
          
      }
    
    
    
    
    • 上述的hasOwnProperty 方法判断属性是否存在,下面的例子检测了对象 o 是否含有自身属性 prop
    o = new Object();
    o.prop = 'exists';
    
    function changeO() {
      o.newprop = o.prop;
      delete o.prop;
    }
    
    o.hasOwnProperty('prop');   // 返回 true
    changeO();
    o.hasOwnProperty('prop');   // 返回 false
    
    • 方法二
    下面两个方法可以实现对象的深复制.
    JOSN对象中的stringify可以把一个js对象序列化为一个JSON字符串,parse可以把JSON字符串反序列化为一个js对象
    // 利用JSON序列化实现一个深拷贝
    function deepClone(source){
      return JSON.parse(JSON.stringify(source));
    }
    var o1 = {
      arr: [1, 2, 3],
      obj: {
        key: 'value'
      },
      func: function(){
        return 1;
      }
    };
    var o2 = deepClone(o1);
    console.log(o2); // => {arr: [1,2,3], obj: {key: 'value'}}
    

    参考

    相关文章

      网友评论

          本文标题:js-引用类型对象拷贝

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