面試考題 2024 - 淺拷貝與深拷貝(實作) ===  --- ###### tags: `面試問題`, `練習問題`, `2024` 其實製作這個系列是為了自己考試的時候可以被深入地刻在腦海裡,殊不知在專案裡都已經用過非常多次,但為了讓面試更容易敘述和讓面試官更了解自己的實力,也只好下點功夫來學習下正確的知識。 ## 什麼是淺拷貝(Shallow Copy) 淺拷貝只會複製對象的第一層屬性。如果對象的屬性值基礎數據類型是 string啊,Number之類的,則會複製其值。 但如果是引用數據類型呢,例如 Array,Object,則會複製其引用而非實際本體。 注意: **如果原始對象和拷貝對象的某個屬性都指向同一個對象時,修改這個對象將影響到兩者!** ## 淺拷貝的實現方式: ```jsx let obj1 = { a: 1, b: { c: 2 } }; let obj2 = Object.assign({}, obj1); obj2.a = 3; obj2.b.c = 3; // 修改obj2中b属性的c属性,也会影响obj1 console.log(obj2); ```  第二種: ```jsx let obj1 = { a: 1, b: { c: 2 } }; let obj2 = { ...obj1 }; obj2.b.c = 3; // 修改obj2中b属性的c属性,也会影响obj1 ``` 以上這兩種充分地表現了淺拷貝的做法。 這裡會發現改變的對象是obj2可是obj1卻也跟著改變。 應驗了上面那句,如果原始對象和拷貝對象的某個屬性都指向同一個對象時,修改這個對象都會影響兩者。 - 當你執行 **obj2.a = 3** 時,你是在修改 **obj2 的 a** 屬性的值。這裡的 **a** 是一個基本數據類型的屬性,所以這個操作僅僅修改了 **obj2 中的 a**, 並沒有影響 **obj1 的 a** - 當你執行 **obj2.b.c = 3** 時,你是在修改 **obj2 中的 b** 屬性指向對象中的 **c屬性**。因為 **b** 是一個引用數據類型的屬性,**obj1 和 obj2 中的 b 實際上指向同一個對象**,所以這個修改同樣影響了 **obj1 中的 b.c** ## 什麼是深拷貝(Deep Copy) 深拷貝複製的對象所有的層級,做法是創建一個完全獨立的副本。 深拷貝確保源對象和拷貝對象在內存中完全獨立,修改拷貝對象不會影響源對象。 簡單說,就是完全地,重新地成立一個新的空array/object, 然後把資料全部完全拷貝過去空的對象。 ## 深拷貝的實作 ```jsx let obj1 = {a:1, b:{c:2}}; let obj2 = JSON.parse(JSON.stringify(obj1)); obj2.b.c =3 ; //這樣做不會影響 obj1 ``` 1. JSON.parse() 和 JSON.stringify(): - 這是實現深拷貝的一個快捷方法,但它不會複製函數和循環引用的對象。 --- ```jsx function deepCopy(obj) { if(obj === null || typeof obj !== "object"){ return obj; } let copiedObject = Array.isArray(obj)? []: {}; for (let key in obj){ if(obj.hasOwnProperty(key)){ copiedObject[key] = deepCopy(obj[key]); } } return copiedObject; } ``` 2. 遞歸拷貝: - 可以自定義函數來遞歸遍歷和複製所有層級,這種方法可以處理複雜的情況,包含函數或循環引用的對象。 --- ```jsx import _ from 'lodash'; let obj1 = {a:1, b:{c:2}}; let obj2 = _.cloneDeep(obj1); obj2.b.c = 3; //不影響obj1 ``` 3. 使用庫 (如 Lodash 的 ._cloneDeep()) - Lodash 提供了一個非常強大的深拷貝函數,可以處理各種類型的數據,包含循環引用等。 ## 總結 簡單說呢,就是臨時的,接下來的操作需要拿出來組合用但又不會間接修改到原本結構的,可以用淺拷貝。 如果是需要重新組合成一個新的引用數據類,擔心會不小心搞到原本object對象的,可以考慮用深拷貝。 當然如果對象較為簡單或只需要拷貝頂層屬性而已,淺拷貝通常更快且消耗最少資源。 希望以上的解說能讓閱讀者學習到新的知識。加油,Peace 
×
Sign in
Email
Password
Forgot password
or
By clicking below, you agree to our
terms of service
.
Sign in via Facebook
Sign in via Twitter
Sign in via GitHub
Sign in via Dropbox
Sign in with Wallet
Wallet (
)
Connect another wallet
New to HackMD?
Sign up