tft每日頭條

 > 生活

 > 深拷貝和淺拷貝的區别及實現

深拷貝和淺拷貝的區别及實現

生活 更新时间:2025-02-12 12:16:29

深拷貝和淺拷貝的區别及實現(原來深拷貝與淺拷貝是這樣)1

深拷貝和淺拷貝的區别及實現(原來深拷貝與淺拷貝是這樣)2

為了讓讀者更好的理解深淺拷貝,在講深淺拷貝之前要引入基本數據類型 , 引用數據類型 和 數據儲存(棧和堆)這幾個概念,如果已經理解,可直接跳過這一part。

JS數據類型

Q:前端面試常問,JS的基本數據類型有哪些呀?

A:JS數據類型分為基本數據類型和引用數據類型,詳細分類如下:

深拷貝和淺拷貝的區别及實現(原來深拷貝與淺拷貝是這樣)3

Q:基本數據類型和引用數據類型的儲存方式有什麼不同?

A:

  • 基本數據類型:變量名和值都儲存在棧内存中,例如:

var num=10;

num變量在内存中儲存如下:

深拷貝和淺拷貝的區别及實現(原來深拷貝與淺拷貝是這樣)4

  • 引用數據類型:變量名儲存在棧内存中,值儲存在堆内存中,但是堆内存中會提供一個引用地址指向堆内存中的值,而這個地址是儲存在棧内存中的,例如:

var arr=[1,2,3,4,5];

arr變量在内存中的儲存如下:

深拷貝和淺拷貝的區别及實現(原來深拷貝與淺拷貝是這樣)5

對這幾個概念有了初步了解之後,接下來正式開始講深淺拷貝。

什麼是淺拷貝和深拷貝

在講兩者概念之前我們先看一個需求:現在有一個對象A,需求是将A拷貝一份到B對象當中?

淺拷貝

當B拷貝了A的數據,且當B的改變會導緻A的改變時,此時叫B淺拷貝了A,例如:

//淺拷貝 var A={ name:"martin", data:{num:10} } var B={} var B=A; B.name="lucy"; console.log(A.name); //lucy

A直接賦值給B後,B中name屬性的改變導緻了A中name屬性也發生了變化。

深拷貝和淺拷貝的區别及實現(原來深拷貝與淺拷貝是這樣)6

其實是因為這種賦值方式隻是将A的堆内存地址賦值給了B,A和B儲存的是同一個地址,指向的是同一個内容,因此B的改變當然會引起A的改變。

淺拷貝的方式

直接賦值

第一種方式就是上面所寫代碼中的将對象地址直接進行賦值。

var A={ name:"martin", data:{num:10} }; var B={}; B=A; B.name="lucy"; console.log(A.name); //"lucy",A中name屬性已改變

Object.assign(target,source)

這是ES6中新增的對象方法,對它不了解的見ES6對象新增方法,它可以實現第一層的“深拷貝”,但無法實現多層的深拷貝。

以當前A對象進行說明

第一層“深拷貝”:就是對于A對象下所有的屬性和方法都進行了深拷貝,但是當A對象下的屬性如data是對象時,它拷貝的是地址,也就是淺拷貝,這種拷貝方式還是屬于淺拷貝。

多層深拷貝:能将A對象下所有的屬性,及時屬性是對象,也能夠深拷貝出來,讓A和B相互獨立,這種叫才叫深拷貝。

var A={ name:"martin", data:{num:10}, say:function(){ console.log("hello world") } } var B={} Object.assign(B,A); //将A拷貝到B B.name="lucy"; console.log(A.name); //martin,發現A中name并沒有改變 B.data.num=5; console.log(A.data.num); //5,發現A中data的num屬性改變了,說明data對象沒有被深拷貝

淺拷貝總結

直接賦值:這種方式實現的就是純粹的淺拷貝,B的任何變化都會反映在A上。

Object.assign():這種方式實現的實現的是單層“深拷貝”,但不是意義上的深拷貝,對深層還是實行的淺拷貝。

深拷貝

當B拷貝了A的數據,且當B的改變不會導緻A的改變時,此時叫B深拷貝了A,例如:

//深拷貝 var A={ name:"martin", data:{num:10}, say:function(){ console.log("hello world") } } //開辟了一個新的堆内存地址,假設為placaA var B={}; //又開辟了一個新的堆内存地址,假設為placeB B=JSON.parse(JSON.stringfy(A)); B.name="lucy"; console.log(A.name); //martin

通過JSON對象方法實現對象的深拷貝,我們可以看到其中B.name值的改變并沒有影響A.name的值,因為A和B分别指向不同的堆内存地址,因此兩者互不影響。

深拷貝的方式

理解了深淺拷貝,接下來說一下深拷貝的幾種方式。

首先假設一個已知的對象A,然後需要把A深拷貝到B。

var A={ name:"martin", data:{num:10}, say:function () { console.log("say"); } }; var B={};

遞歸賦值

function deepCopy(A,B) { for(item in A){ if(typeof item=="object"){ deepCopy(item,B[item]); }else{ B[item]=A[item]; } } } deepCopy(A,B); B.data.num=5; console.log(A.data.num); //10,A中屬性值并沒有改變,說明是深拷貝

通過這種方式能實現深層拷貝,而且能自由控制拷貝是如何進行的,如:當B中有和A同名的屬性,要不要重新賦值?這些都可以進行控制,但是代碼相對複雜一些。

JSON.parse()和JSON.stringify

var B=JSON.parse(JSON.stringify(A)); B.data.num=5; console.log(A.data.num); //10,A中屬性值并沒有改變,說明是深拷貝

用這種方式實現深拷貝的時候要 注意 , 函數是無法進行拷貝的,會被丢失 ,上述代碼中B也并沒有拷貝出A中的say函數,這和JSON.stringify方法的規則有關系,它在序列化的時候會直接忽略函數,因此最後A中的say函數沒有被拷貝到B,關于JSON.stringify序列化的具體規則見JSON.stringify指南。

深拷貝總結

遞歸:使用遞歸進行深拷貝時比較靈活,但是代碼較為複雜;

JSON對象:JSON對象方法實現深拷貝時比較簡單,但是當拷貝對象包含方法時,方法會被丢失;

因此使用者可按自身的使用場景來選擇拷貝方式

,

更多精彩资讯请关注tft每日頭條,我们将持续为您更新最新资讯!

查看全部

相关生活资讯推荐

热门生活资讯推荐

网友关注

Copyright 2023-2025 - www.tftnews.com All Rights Reserved