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

    在JavaScript中,存在着这样的两种拷贝方式。分别是:深拷贝和浅拷贝,这两种拷贝在实际中非常的常见,如果读者是一个阅读源码的爱好者,相信多多少少对深拷贝和浅拷贝有所了解。

    一、浅拷贝

    浅拷贝在现实中最常见的表现在赋值上面,例如

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>测试</title>
    </head>
    <body>
        <script type="text/javascript">
            //第一个数组
            var test=["1","2","3"];
            //第二个数组
            var test2=[];
            test2=test;
            test2[1]="two";
            console.log(test);//运行的结果是["1","two","3"]
        </script>
    </body>
    </html>

    从上面的例子,我们修改test2数组的值,最后打印test数组,发现test也跟着改变了。

    其实这个就是一个最浅的浅拷贝,相当于test2=test这个阶段是在将test数组中的存储地址索引赋值给test2数组,所以两个数组都是指向同一块存储地址中去。

    除了这种方法可以实现浅拷贝,还有使用slice和concat进行浅拷贝

    例如:我们测试一次slice这个方法

    <script type="text/javascript">
        var arr=["demo1","demo2","demo3"];
        var arr2=arr.slice(0);
        arr2[1]="test";
        console.log(arr);//["demo1","demo2","demo3"]
        console.log(arr2);//["demo1","test","demo3"]
    </script>

    从上面的例子我们可以看出,使用slice方法对数组进行了深度拷贝,

    同理,concat的用法如下

    <script type="text/javascript">
        var arr=["demo1","demo2","demo3"];
        var arr2=arr.concat();
        arr2[1]="test";
        console.log(arr);//["demo1","demo2","demo3"]
        console.log(arr2);//["demo1","test","demo3"]
    </script>

    为何这样已经算得上是深拷贝的东西,我又称之为浅拷贝呢?

    其实使用slice和concat这两个方法部分都是不可以拷贝如下的这种情况的:

    运行如下的代码:

    <script type="text/javascript">
        var arr = [1,3,[4,7,65,9]];
        var arr1=arr.slice(0);
        arr1[2][2]=2;
        console.log(arr1[2][2]);
        console.log(arr);
    </script>

    或者是如下的这一段代码: 

    <script type="text/javascript">
        var arr = [1,3,[4,7,65,9]];
        var arr1=arr.concat();
        arr1[2][2]=2;
        console.log(arr1[2][2]);
        console.log(arr);
    </script>

    我们都可以看到,我们拷贝了arr的值,然后同时修改arr1的值,我们可以看到arr也被修改了。

    所以对于Slice和concat这两个方法来说都是浅拷贝,只能拷贝数组中的第一层

    另外除了可以对数组进行浅拷贝,同样的我们也可以对JSON数据进行浅拷贝

    assign这个方法可以对object对象进行复制,但是这种拷贝是浅拷贝跟直接赋值却又是不一样的。

    assign其中接受两个参数,第一个参数指代的是拷贝之后需要修改的内容,第一个参数指代的是要拷贝的内容

    <script type="text/javascript">
        var obj = { a: {a: "hello", b: 21} }; 
        var initalObj = Object.assign({b:{"test":1111}}, obj); 
        initalObj.a.a = "changed"; 
        console.log(obj);
        console.log(initalObj);
        console.log(obj.a.a); // "changed"
        console.log(obj===initalObj);//false
    </script>

    运行上面的代码可以看到,obj 里面的值也被修改了

    二、深拷贝

     最简单的深拷贝就莫过于使用JSON对象提供的方法。

     我们先来个例子测试一下:

    <script type="text/javascript">
        var json={
            "a":"test",
            "b":"test1"
        };
        var b=JSON.parse(JSON.stringify(json));
        b.a="demo";
        console.log(json);//{"a":"test","b":"test1"}
    </script>

    我们修改了b中的值,但是打印json对象发现没有被修改到,这个已经就是深度拷贝的。

    但是转换后的原来的值类型会出现丢失,也就是最后的类型一定是Object类型。

    说道深拷贝,就不能不提Jquery中中的extend方法,这个方法如果是有学习制作插件的同学应该都会知道,这个方法用于生成一个全新的JSON对象值。

    其实这个本身就是一种深拷贝的应用,具体的代码如下:

        <script src="https://cdn.bootcss.com/jquery/3.2.1/jquery.js"></script>
        <script type="text/javascript">
            var arr=["test",["demo1","demo2"]];
            var arr1=$.extend({},arr);
            arr[1][0]=1;
            console.log(arr1);
        </script>

    上面的代码运行的时候,我们可以看到即使是数组也是同样可以深度拷贝的。

    具体的解释是:因为上面我们已经说过数组类型其实就是一种object类型,那么extend方法是用来对object类型进行深拷贝的,那么也就是满足了数组的这一种情况,当然博主是没有去看源码的,所以如果解释与源码有出入,望请指正。

    说一说最后的一种实现深拷贝的方法吧,也就是遍历原对象,并将原对象赋值给生成后的对象,具体的方式详见:

    http://blog.csdn.net/hj7jay/article/details/51986486

  • 相关阅读:
    题解 P3717 【[AHOI2017初中组]cover】
    【题解】 [POI2012]FES-Festival (差分约束)
    【题解】 [HNOI2005]狡猾的商人(差分约束)
    【题解】 [SCOI2011]糖果 (差分约束)
    【题解】 POJ 1201 Intervals(差分约束)
    【题解】 Codeforces 919F A Game With Numbers(拓扑排序+博弈论+哈希)
    【题解】 [ZJOI2012]灾难 (拓扑排序+LCA)
    【题解】 [HAOI2016]食物链 (拓扑排序)
    【题解】 Luogu P1402 酒店之王 (二分图匹配)
    【题解】 [NOI2009]变换序列 (二分图匹配)
  • 原文地址:https://www.cnblogs.com/st-leslie/p/7128765.html
Copyright © 2011-2022 走看看