zoukankan      html  css  js  c++  java
  • 《JavaScript总结》深拷贝和浅拷贝

    在javascript中,数据主要分基本类型和引用类型两种。

    基本类型的赋值比较简单,但是引用类型的赋值,会存在一些问题,那我们用代码来分析一下。

    一、浅拷贝

    var one = "测试1";
    var two = one;
    two = "测试2";
    console.log(one);

    上面代码中,声明了一个变量one ,值为:“测试1” ,然后将变量one 赋值给了变量two ,

    之后我们把变量two的值修改成:“测试2” 了,这时我们从控制台打印变量one ,输出的结果是:“测试1”。

    也就是说修改变量two的值并不会对变量one造成影响。

    那我们再来看下面这个例子:

    var arr = ['白色','蓝色','紫色'];
    var temp = arr;
    temp[1]="天蓝色";
    console.log(arr);

    上面这段代码,控制台打印输出了  ‘白色’,'天蓝色','紫色'  ,这是怎么回事呢?我们明明修改的是temp,怎么arr也被修改了?

    这其实很简单,因为在javascript中,数组属于引用类型数据。在上面的例子中,当把arr赋值给temp时,其实只是把访问地址赋值给了temp 

     

    我们来分析一下代码

     

    var arr = ['白色','蓝色','紫色'];

    在javascript中,数组的大小是不确定的,这时js会在堆内存中建立一块内存,用来存一个数组,而这个数组的值目前为:['白色','蓝色','紫色'] ,然后会生成一个地址,并且赋值给了arr ,

    所以说arr存的是 ['白色','蓝色','紫色'] 在堆内存中的访问地址。

     

    var temp = arr;

    因为arr存的是一个地址,这时将arr赋值给了temp ,所以temp也拥有访问['白色','蓝色','紫色']的地址了。

     

    temp[1]="天蓝色";

    那么这时我们将temp[1]的值修改成了“天蓝色”,这一操作,首先temp通过地址访问堆内存对应的数据,并且修改了数据。

    因为arr和temp存的只是访问同一个源的地址,源被temp改变了,arr再次访问时,访问的也就是改变过的源了。

     

    但有时候,我们修改一个数据的时候,并不想影响另一个数据,使用深拷贝就可以解决这个问题。

    二、深拷贝

    数组中的深拷贝

    数组实现深拷贝的方法:使用slice()或cancat()方法,或者是使用循环将当前数组的值,一个一个添加到新的数组中即可。

    var arr = [1,3,4];
    var temp = arr.slice(0);
    temp[0]=6;
    console.log(arr);//输出 1,3,4  不会被temp影响
    var arr = [1,3,4];
    var temp =arr.concat([]);
    temp[0]=6;
    console.log(arr);//输出1,3,4 不会被temp影响

    其实上面两种都属于简单的深拷贝,如果是二维数组、三维数组呢?我们看一个例子

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

    控制台输出结果如下:

    使用了简单的深拷贝(slice方法)之后,可以发现ac的第一个值确实不受ad的影响,但是ac的第二个值却随着ad的改变而改变了。更深层的拷贝怎么办呢?其实可以利用递归函数来解决这个问题

            var duowei = [1,[2,3],4];
            function dispose(data){
                var out = [];
                for(var i =0;i<data.length;i++){
                    if(data[i] instanceof Array){
                        out[i]=dispose(data[i]);
                    }else{
                        out[i]=data[i];
                    }
                }
                return out;
            }
    
            var result = dispose(duowei);
            result[1][0]=9;
            console.log(duowei);        

    对象中的深拷贝

    在对象中简单的深拷贝可以使用Object.assign来实现

    let a = {
        age: 1
    }
    let b = Object.assign({}, a)
    a.age = 2
    console.log(b.age) // 1

    复杂的深拷贝可以使用JSON.parse(JSON.stringify(object))来解决,不过这个方法有一些局限性。

    • 会忽略 undefined
    • 会忽略 symbol
    • 不能序列化函数
    • 不能解决循环引用的对象
    let a = {
        age: 1,
        jobs: {
            first: 'FE'
        }
    }
    let b = JSON.parse(JSON.stringify(a))
    a.jobs.first = 'native'
    console.log(b.jobs.first) // FE

    其实方法有很多,需要自己去挖掘。

    这里在分享一个数组和对象实现简单深拷贝通用的方法:通过展开运算符(…)来实现。

    let a = {
        age: 1
    }
    let b = {...a}
    a.age = 2
    console.log(b.age) // 1
  • 相关阅读:
    java初级应用------>判断某个字符串是否满足一定的格式要求------>使用正则表达式判断是否满足格式要求
    java基础---->数据结构与算法---->Java API:集合 以及 排序相关API
    Spring Framework------>version4.3.5.RELAESE----->应用实例------->测试spring framework的IOC功能
    Spring MVC------->version4.3.6-------->知识点------>实现Controller(编程思路)
    Spring MVC------->version4.3.6-------->知识点------>DispatchServlet和它对应的WebApplicationContext
    Spring MVC------->version4.3.6-------->概述
    数据结构与算法----->数据结构----->树------->二叉树的遍历
    多态 / 面向接口编程
    sqlserver存储过程的使用
    sqlserver数据库中sql的使用
  • 原文地址:https://www.cnblogs.com/Mrrabbit/p/10443705.html
Copyright © 2011-2022 走看看