javascript深拷貝和淺拷貝

在JavaScript中,存在着這樣的兩種拷貝方式。分別是:深拷貝和淺拷貝,這兩種拷貝在實際中很是的常見,若是讀者是一個閱讀源碼的愛好者,相信多多少少對深拷貝和淺拷貝有所瞭解。javascript

 

1、淺拷貝

淺拷貝在現實中最多見的表如今賦值上面,例如css

<!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也跟着改變了。html

其實這個就是一個最淺的淺拷貝,至關於test2=test這個階段是在將test數組中的存儲地址索引賦值給test2數組,因此兩個數組都是指向同一塊存儲地址中去。java

除了這種方法能夠實現淺拷貝,還有使用slice和concat進行淺拷貝jquery

例如:咱們測試一次slice這個方法json

 

<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這兩個方法部分都是不能夠拷貝以下的這種狀況的:spa

運行以下的代碼:

 

<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 裏面的值也被修改了

 

2、深拷貝

 最簡單的深拷貝就莫過於使用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

相關文章
相關標籤/搜索