2017年1月16日 星期一

[JavaScript]淺談使用jQuery套件JavaScript物件複製

最近在前端開發需要做物件複製,但有趣的是JavaScript是call by value reference(或稱call by sharing),每個變數存放的都是資料的記憶體位置。
簡單一點來記的話就是在JavaScript中,原始型別(Primitive Type)的使用「看起來」像是call by value,而物件(除原始型別外全部都是)的使用「看起來」像是call by reference。

注意一點,以上說法只是描述在操作上類似於如此,而JavaScript實際上的記憶體操作是call by value reference(或稱call by sharing)。

詳細的說明或狀況,等我哪天有空我再來補補好了。

p.s. 強烈建議可以去上保哥的JavaScript 開發實戰:核心概念篇,上了課之後會有更深入的了解,雖然我也已經忘了很多...
我對不起保哥啊!

好啦~說了這麼多背景與廢話後,回到本篇主要探討的「物件複製」來看一個例子。
var originObject = {a: {c: 3,d: 4},b: 2};
var copyObject = originObject;

copyObject.b = 5;
console.log(originObject); //{a: {c: 3,d: 4},b: 5}
console.log(copyObject); //{a: {c: 3,d: 4},b: 5}
//兩個物件都中的b屬性都被更動了

可以發現,originObject以及copyObject皆指向同一塊記憶體位置,因為originObject物件中的a值也跟著改變了。
為了達成完全複製目前我所知道最方便最好用的方法就是使用jQuery的extend了。

用法如下:
var originObject = {a: {c: 3,d: 4},b: 2};
var copyObject = $.extend(true,{},originObject);
//$.extend([啟用深層複製],[合併基底物件],[欲合併的物件])

copyObject.b = 5;
console.log(originObject); //{a: {c: 3,d: 4},b: 2}
console.log(copyObject); //{a: {c: 3,d: 4},b: 5}
//可以發現只有copyObject.b被異動了

extend方法目的其實為將兩個物件做合併的動作,而這裡是將一個空物件與originObject作合併,就可以做出類似複製物件的作用啦!

至於啟用深層複製這件事,則關係到了整個物件是否為完全的複製一份,以下有個例子:
//----------------------啟用深層複製---------------------------
var originObject = {a: {c: 3,d: 4},b: 2};
var copyObject = $.extend(true,{},originObject); //使用深層複製

copyObject.a.c = 5;
copyObject.b = 5;
console.log(originObject); //{a: {c: 3,d: 4},b: 2}
console.log(copyObject); //{a: {c: 5,d: 4},b: 5}
//可以發現只有copyObject.a.c以及copyObject.b被異動了
//----------------------關閉深層複製---------------------------
var originObject = {a: {c: 3,d: 4},b: 2};
var copyObject = $.extend(false,{},originObject); //關閉深層複製

copyObject.a.c = 5;
copyObject.b = 5;
console.log(originObject); //{a: {c: 5,d: 4},b: 2}
console.log(copyObject); //{a: {c: 5,d: 4},b: 5} 
//可以發現兩個物件下的屬性a中的c皆被異動了,而另外只有copyObject.b有被異動了

從例子中可以看出深層複製的真實執行結果,啟用深層複製會將整個物件,完完整整的複製一份。
而淺層複製,只有第一個層級的屬性(內容非物件類型的屬性)有被複製,而第一層屬性為物件類型的,則同樣指向同一份記憶體位置。

謝謝收看!

參考資料:
What is the most efficient way to deep clone an object in JavaScript?
http://stackoverflow.com/questions/122102/what-is-the-most-efficient-way-to-deep-clone-an-object-in-javascript
[Javascript] 關於 JS 中的淺拷貝和深拷貝
http://larry850806.github.io/2016/09/20/shallow-vs-deep-copy/
[筆記] 談談JavaScript中by reference和by value的重要觀念
http://pjchender.blogspot.tw/2016/03/javascriptby-referenceby-value.html

沒有留言:

張貼留言