標籤:img 影響 log 導致 傳遞 進階 port 開始 方式
在理解JS的深淺複製之前,我覺得有必要先提及一下關於值傳遞與引用傳遞。
在JS中,基本類型值的複製是按值傳遞的,而參考型別值的複製則是按引用傳遞的。值傳遞複製的對象間不會有任何牽連,互相獨立;但是引用傳遞複製的對象間則會相互影響,修改其中任何一方的值都會在另一方中體現。之所以會有這樣的表現和JS的記憶體機制有關。
JS的記憶體也分為堆和棧,注意這裡的堆棧和資料結構的堆棧是不同的概念。
棧:由系統自動分配,自動回收,效率高,但容量小
堆:由程式員手動分配記憶體,並且手動銷毀(進階語言如JS中有垃圾自動回收機制),效率不如棧,但容量大
JS定義的基本類型值會被存放在棧中,而參考型別因為其大小不固定,系統會為參考型別分配堆記憶體空間存放,而只將指向該堆記憶體空間的指標(即引用)存放在棧中。這樣一來,我們訪問參考型別值時,實質上只是在訪問它的引用,然後再按照這個引用地址去堆中找到它的實際內容。
所以當複製的時候,對於基本類型值變數,系統會為新變數單獨開闢一個新的棧記憶體空間,並將源變數的值複製一份儲存到裡面。而對於參考型別值,新變數複製得到的只是引用對象的記憶體位址,這麼一來,通過兩個變數的引用訪問到的實質就是同一個參考型別對象了。所以才會出現對一方參考型別值的修改導致了另一方訪問到的參考型別值也發生了同步的變化這樣的情況。
淺複製是指在複製對象的時候,只對對象的第一層索引值進行複製。
在上面的例子當中,如果不希望修改 new_person 對象的 name 值的時候,來源物件的 name 值也跟著一起改變,那麼我們可以嘗試對複製過程做一些處理,而不再是直接的賦值拷貝。
這時候我們修改了複製對象的 name 值,來源物件的 name 不會再跟著改變了,但是當我們修改屬性 sport 的值的時候,來源物件的 sport 卻又跟著改變了。
前面也說了,我們的淺複製只是對第一層索引值進行的複製,當來源物件內部還嵌套著其它的對象的時候,又會出現一開始遇到的情況了。複製對象的 love 屬性複製的是來源物件 love 屬性所對應對象的地址,所以也導致了複製對象和來源物件的 love 屬性指向的都是堆記憶體中同一塊記憶體位址。Object.assign( )方法所實現的也是淺複製。 那如何才能完全獨立的複製出一份呢?其實只要遞迴下去,對內部屬性的值仍是對象的再次進入對象內部對其屬性值一一複製即可。 對象深複製還可以藉助 JSON 實現。 但是這種方式實現的深複製會忽略掉值為 undefined 和 函數運算式 的屬性。
Javascript 淺複製與深複製