淺層複製 Shallow Copy
複製一個或多個物件自身所有可數的屬性到另一個目標物件。回傳的值為該目標物件。
上面不容易理解,直接上範例比較清楚:
1 | /* 問題 */ |
- Object.assign
1 | var a = { |
Object.assign 也可改寫成 ES6:
1 | var a = { |
然後淺層複製只會複製第一層物件,若是修改到內層物件屬性,仍會改變原本物件的屬性值
1 | var a = { |
這是因為內層的 age 仍指向原本的參考,並不會一起複製勒。
深層複製 Deep Copy
只需要將物件轉換成純值,在轉換成物件即可
- JSON.parse() with JSON.stringify()
1 | var a = { |
然而此方法僅限用於 json 格式,屬性值不能是undefined、NaN或是function,否則會無法轉換。
1 | var a = { |
深層複製完美解法
一般會參考第三方工具的深層複製寫法,當然如果是高手等級,就乾脆自己寫一個插件也不是不行。
- Underscore — _.clone()
此方法只能算是半個深層複製,也就是說不會完全複製物件內的參考。
1 | /* 請先引入 Underscore,否則會出錯 */ |
- jQuery — $.extend()
1 | /* 請先引入 jQuery,否則會出錯 */ |
注意,undefined 不會被複製到哩。
- lodash — .clone() or.cloneDeep()
_.clone(obj, true)等於_.cloneDeep(obj)
lodash 在深層複製上更優於 jQuery、Underscore,畢竟原始碼上就多了幾百行啊。
1 | /* 請先引入 lodash,否則會出錯 */ |
lodash的_.cloneDeep()幾乎完美複製原本的物件內容。
效能&功能比較
| 特性 | jQuery | lodash | JSON.parse |
|---|---|---|---|
| 瀏覽器兼容性 | IE6+ (1.x) & IE9+ (2.x) | IE6+ (Compatibility) & IE9+ (Modern) | IE8+ |
| 能夠深複製內層所有屬性值 | 回傳異常 RangeError: Maximum call stack size exceeded | 支持 | 回傳異常 TypeError: Converting circular structure to JSON |
| 對 Date, RegExp 的深層複製支持 | × | 支持 | × |
| 對 ES6 新引入的標準對象的深層複製支持 | × | 支持 | × |
| 複製陣列的属性 | × | 僅支持RegExp#exec返回的陣列结果 | × |
| 是否保留非原生對象的類型 | × | × | × |
| 複製不可枚舉元素 | × | × | × |
| 複製函數 | × | × | × |
| 方法 | jQuery | lodash | JSON.parse |
|---|---|---|---|
| 平均 | 478 | 293 | 656 |
倘若需要使用到深層複製的話,還是會先以 loadsh 為優先哩。
參考資料
六角學院 - JavaScript 核心篇
JavaScript 核心觀念(30)-物件-淺層複製及深層複製
深入剖析 JavaScript 的深复制