在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>
上面的代碼運行的時候,我們可以看到即使是數組也是同樣可以深度拷貝的。