zoukankan      html  css  js  c++  java
  • javascript的深浅拷贝

    查阅资料,看到有关深浅拷贝上面的误区,有人说数组的slice()与concat()方法实现的是深拷贝。对此我做了一些尝试并详细理了一下关于js的深浅拷贝问题。首先我们要知道数据类型的存储方式——

    基本类型和引用类型

    js中变量分为两类:

    基本类型:undefined,null,字符串,数值,布尔

    引用类型:统称为object。具体的有Object,Array,Function等

    重点是这两种类型的存储方式了:基本类型的数据是存放在栈内存中的,而引用类型的数据是存放在堆内存中的。

    基本数据类型,是这个样子的:

     

    引用类型保存在堆中,栈内的是变量的标识符以及对象在堆内存中的存储地址,当需要访问引用类型(如对象,数组等)的值时,首先从栈中获得该对象的地址指针,然后再从对应的堆内存中取得所需的数据。

    所以对于这两种类型的赋值是有不同的:

    当你在复制基本类型的时候,相当于把值也一并复制给了新的变量。修改值的时候也不会影响另一个变量的值。

    而在复制引用类型的时候,实际上只是复制了指向堆内存的地址,即原来的变量与复制的新变量指向了同一个东西。

    例1.改变a,会影响b

    var a = {name:"peri",age:20};
    var b = a;
    console.log(a === b);
    a.age = 30;
    console.log(a);
    console.log(b);
    

    深浅拷贝

    对于仅仅是复制了引用(地址),即原来的变量和新的变量指向同一个地址,彼此之间的操作会互相影响,为浅拷贝

    而如果是在堆中重新分配内存,拥有不同的地址,复制后的对象与原来的对象完全隔离,互不影响,为深拷贝

    深浅拷贝的主要区别就是:复制的是引用(地址)还是复制的是实例。

    深拷贝的实现

    1.递归 

    对于例1,我们可以通过递归的方式来实现深拷贝,对引用类型进行遍历,一直到是基本类型为止。

    function deepClone(source){    
        if(!source && typeof source !== 'object'){      
            throw new Error('error arguments', 'shallowClone');    
        }    
        var targetObj = Array.isArray(source) ? [] : {};    
        for(var keys in source){     
            //只遍历对象自身的属性,而不包含继承于原型链上的属性。  
            if(source.hasOwnProperty(keys)){          
                if(source[keys] && typeof source[keys] === 'object'){  
                    targetObj[keys] = deepClone(source[keys]);    //递归      
                }else{            
                    targetObj[keys] = source[keys];         
                }       
            }    
        }    
        return targetObj; 
    }
    var a = {name:"peri",age:20};
    var b = deepClone(a);
    console.log(a === b);
    a.age = 18;
    console.log(a);
    console.log(b);
    

    2.JSON 对象的 parse 和 stringify

    stringify把一个 js 对象序列化为一个 JSON 字符串。parse把 JSON 字符串反序列化为一个 js 对象,这两个方法实现的是深拷贝。

    var obj = {name:'pp',age:24,company : { name : 'AAA', address : '深圳'} };
    var obj_json = JSON.parse(JSON.stringify(obj));
    console.log(obj === obj_json);
    obj.company.name = "BBB";
    obj.name = "peri";
    console.log(obj);
    console.log(obj_json);
    

    3.jQuery中的 extend方法

    jQuery的$.extend方法是我们在开发中经常用到的方法,用于合并若干个对象。

    可用于深浅拷贝,第一个参数为true深拷贝。为false或者没有为浅拷贝。

    例2.深拷贝

    var obj = {name:'pp',age:24,company : { name : 'AAA', address : '深圳'} };
    var obj_json = $.extend(true, {}, obj);
    console.log(obj === obj_json);
    obj.company.name = "BBB";
    obj.name = "peri";
    console.log(obj);
    console.log(obj_json);

    例2.2浅拷贝

    slice()与concat()方法

    最后再来讨论一下最初关于数组的slice()与concat()方法是否深拷贝。

    例3.slice()方法

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

    可以看到,改变a并没有影响b!那么就说明slice()是深拷贝了吗?没有那么简单!

    例3.1

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

    这很明显说明slice()不是深拷贝!

    原来Array 的 slice() 和 concat ()方法,对于第一层的值都是深拷贝而到第二层的时候 Array的slice() 和 concat()方法就是复制引用 。(concat与slice结果相同,这里不再举例)。

  • 相关阅读:
    Chap-6 6.1~6.3 程序装载
    X Window基础二(转)
    X Window基础一(转)
    Linux基础命令 su与sudo的区别
    Chap-4 Section 4.6 链接控制过程
    Chap-4 Section 4.5 静态库链接
    ceph的CRUSH数据分布算法介绍
    使用ffmpeg捕获USB外部摄像头视频流
    使用ffserver实现转发实时流媒体(摄像头捕获)
    内存映射文件(专门读写大文件)
  • 原文地址:https://www.cnblogs.com/PeriHe/p/8718017.html
Copyright © 2011-2022 走看看