做者:Chris Chu翻譯:瘋狂的技術宅javascript
原文:https://alligator.io/js/deep-...前端
未經容許嚴禁轉載java
若是你打算用 JavaScript 進行編碼,那麼就須要瞭解對象的工做方式。對象是 JavaScript 最重要的元素之一,深刻理解了它會使你在編碼時駕輕就熟。在克隆對象時,它並不像看起來那麼簡單。程序員
當你不想改變原始對象時,就須要克隆對象。例如,若是你有一個接受對象並改變它的函數,可能不想改變其原始對象。面試
那麼讓咱們在 JavaScript 中建立一個對象:segmentfault
let testObject = { a: 1, b: 2, c: 3 };
在上面的代碼片斷中,咱們初始化一個新對象並將其分配給變量 testObject
。如今對於大多數初學者來講,他們會試着經過將 testObject
分配給新變量來建立這個對象的副本,以便在其代碼中進行操做。很抱歉用這種方法行不通。服務器
下面是一個代碼片斷,說明了爲何不起做用。微信
let testObject = { a: 1, b: 2, c: 3 }; // 爲 testObject 建立一個副本 let testObjectCopy = testObject; testObject.a = 9; console.log(testObjectCopy.a); // 這裏 a = 9
如上面的代碼片斷所示,建立新變量 testObjectCopy
實際上並不建立 testObject
的副本。相反它只是引用 testObject
。你對所謂的副本作的任何更改也將反映在原始對象中。多線程
循環遍歷對象並將每一個屬性複製到新對象也不起做用。框架
const copyObject = object => { // 這是存儲原始對象屬性的對象 let copiedObj = {}; for (let key in object) { // 這裏將每一個屬性從原始對象複製到複製對象 copiedObj[key] = object[key]; } return copiedObj; }; const testObject = { a: 5, b: 6, c: { d: 4 } }; copyObject(testObject);
上述方法存在如下幾個問題:
for
循環和 Object.keys
中的屬性。Object.prototype
方法,這不是複製對象時所需的方法。configurable
或 writable
設置爲 false
,則複製對象中的屬性描述符將會默認爲 true
。對於僅存儲基本類型(如數字和字符串)的簡單對象,上述淺層複製方法將起做用。可是若是對象具備對其餘嵌套對象的引用,則不會複製實際對象。你只會複製對其的引用。
對於深層複製,最簡單的選擇是使用可靠的外部庫,如Lodash。
Lodash 提供兩種不一樣的功能,容許你進行淺拷貝和深拷貝,它們是 clone
和 clonedeep
。 Lodash 的優勢在於你能夠單獨導入它的每一個函數,而無需將整個庫放入你的項目中。這能夠大大的減小依賴項的大小。
const clone = require('lodash/clone'); const cloneDeep = require('lodash/clonedeep'); // 你也能夠這樣作: // const clone = require('lodash.clone'); // const cloneDeep = require('lodash.clonedeep'); // 取決於你本身的風格 :)
如今就用 clone
和 clonedeep
函數作一些嘗試:
const clone = require('lodash/clone'); const cloneDeep = require('lodash/clonedeep'); const externalObject = { animal: 'Gator' }; const originalObject = { a: 1, b: 'string', c: false, d: externalObject }; const shallowClonedObject = clone(originalObject); externalObject.animal = 'Crocodile'; console.log(originalObject); console.log(shallowClonedObject); // originalObject 和 shallowClonedObject 中的`animal`屬性 // 是同時被改變的,由於它是一個淺的副本。 const deepClonedObject = clonedeep(originalObject); externalObject.animal = 'Lizard'; console.log(originalObject); console.log(deepClonedObject); // 原始對象中的'animal'屬性發生了變化,但對於 // deepClonedObject,它複製後仍然是'Crocodile' // 對象是獨立的而不是複製引用。
在上面的代碼中,咱們建立了一個名爲 originalObject
的對象,它存儲了 7 個屬性,每一個屬性都有不一樣的值。屬性 d
引用咱們的 externalObject
,它具備值爲 Gator
的 animal
的屬性。
當從 Lodash 執行 clone
函數時,它會建立一個對象的淺層副本,咱們將其分配給 shallowClonedObject
。在 externalObject
中爲 animal
屬性賦值一個新值將改變 originalObject
和 shallowClonedObject
,由於淺拷貝只能將引用複製到 externalObject
並它沒有爲本身創造一個全新的對象。
這就是 clonedeep
函數的用武之地。若是你對 deepClonedObject
執行相同的處理,那麼 originalObject
的 d
屬性是惟一要改變的屬性。
🤓試一試,看看它如何幫助你編碼!🚀