JavaScript:物件:如何複製一個物件?淺拷貝與深拷貝
回顧一下,我們對傳參的討論,物件的傳參是引用傳遞,我們傳遞的是物件資料所在的記憶體地址;
那麼無論我們怎麼去賦值,所有變數指向的都是同一塊記憶體;
如上圖所示,無論我去使用哪個變數去操作物件的屬性,改變的始終是同一塊記憶體區域的資料;
現在,我希望可以將obj1的記憶體資料,完整複製一份,存放到另一個記憶體區域obj2,使得這兩塊記憶體,儲存的資料內容完全一樣,但是我改變其中一塊記憶體的資料,都不會影響到另一塊記憶體的資料;
想一想,我們應該怎麼做,才能達到這一目的?
淺拷貝
能想到的,是遍歷物件的屬性(基本資料型別),然後依次賦值給另一個物件的屬性,因為說到複製,就是指值傳遞,只有基本資料型別是值傳遞:
如上圖所示,我們遍歷了obj1的屬性,並賦值給了obj2,我們修改了obj2的name1屬性,但是並沒有改變obj1的name1屬性,證明我們成功複製了一份obj1的記憶體資料;
那我們每次都需要用for-in迴圈嗎?JS有沒有自帶一些方法來實現淺拷貝呢?
有的:
-
Object.assign()方法
語法為
Object.assign(dest, src1, src2,,,,,)
第一個變數
dest
是目標物件,即將後面的物件的屬性值複製給目標物件;後面的所有變數
src
即是源物件,會將所有源物件的屬性值全複製給目標物件,如果有屬性名同名,則會進行覆蓋;呼叫該方法,結果會返回dest;
深拷貝
現在假設,obj1中,name1是一個物件型別,上面的拷貝方式,還行得通嗎?
看上圖,obj2對name1的name屬性修改為了Bob,而obj1的name1的name屬性,輸出結果也為Bob,這意味著,obj1和obj2的name1屬性指向的是同一塊記憶體區域;
這是因為,物件是引用傳遞,我們在呼叫Object.assign()方法時,只是將obj1的name1的記憶體地址,複製給了obj2的name1,此時他們之間的記憶體關係,如下所示:
也就是說,此時obj1和obj2並不完全互相獨立,他們之間還共同管理著name1這塊記憶體;
這種不完全互相獨立的拷貝,我們稱之為淺拷貝
所以,完全互相獨立的拷貝,我們就稱之為深拷貝;
那麼,我們怎樣才能實現深拷貝,使兩者完全互相獨立呢?
可行的方法是,對name1這個物件,再進行一次淺拷貝。
這樣太麻煩了,JS有沒有自帶的深拷貝的方法呢?
很遺憾,並沒有。我們需要通過引入其他庫,呼叫庫方法,來進行深拷貝,這裡不贅述。