在 JavaScript 的世界中,物件 Object 的傳遞由於是 By Reference 的緣故,當需要複製一份物件時,就得注意自己的複製型式。這篇筆記下各種淺拷貝、深拷貝的效能比較。
類型
淺複製( 拷貝, Shallow Copy )
適用於僅有一層子層的模式,且每個 key 對應的 value 必須為 Primitive Type。否則第二層之後的值,會依舊是 Pass By Reference,而沒有達成一般認知上的「複製」。
深複製( 拷貝, Deep Copy )
每一層的 key, value 都是完整的用 Pass By Value 複製出來,你可以自由的操作複製出來的值,而不用擔心不小心改動的原有的物件。
效能比較
這篇是挖取 Stack Overflow 上的討論串中的回應,有人做出詳加的比較。有興趣可以點擊以下連接觀看:
https://stackoverflow.com/a/61523278
淺拷貝跑分結果:https://jsbench.me/t0k9l64319/1
深拷貝跑分結果:https://jsbench.me/euk9l6x9jx/1
Shallow Copy 部分
- 使用 ES6 語法的 { … obj } 或是 Object.assign({}, obj) 都是不錯的方式
- 用 JSON.stringify(obj) 的效能不佳
Deep Copy 部分
- 常見的 lodash 資料庫的 cloneDeep 方法,速度跑分大概在中等
- 用 JSON.stringify(obj) 的效能不佳
- 推薦可以使用以下的方法,原理是利用遞迴便利每一個 key 中的每一個 value,再給予輸出
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
function cloneSO(obj) { // Handle the 3 simple types, and null or undefined if (null == obj || "object" != typeof obj) return obj; // Handle Date if (obj instanceof Date) { var copy = new Date(); copy.setTime(obj.getTime()); return copy; } // Handle Array if (obj instanceof Array) { var copy = []; for (var i = 0, len = obj.length; i < len; i++) { copy[i] = cloneSO(obj[i]); } return copy; } // Handle Object if (obj instanceof Object) { var copy = {}; for (var attr in obj) { if (obj.hasOwnProperty(attr)) copy[attr] = cloneSO(obj[attr]); } return copy; } throw new Error("Unable to copy obj! Its type isn't supported."); } |