做者:Chris Chujavascript
翻譯:瘋狂的技術宅前端
原文:alligator.io/js/deep-clo…java
未經容許嚴禁轉載前端工程化
若是你打算用 JavaScript 進行編碼,那麼就須要瞭解對象的工做方式。對象是 JavaScript 最重要的元素之一,深刻理解了它會使你在編碼時駕輕就熟。在克隆對象時,它並不像看起來那麼簡單。函數
當你不想改變原始對象時,就須要克隆對象。例如,若是你有一個接受對象並改變它的函數,可能不想改變其原始對象。工具
那麼讓咱們在 JavaScript 中建立一個對象:ui
let testObject = {
a: 1,
b: 2,
c: 3
};
複製代碼
在上面的代碼片斷中,咱們初始化一個新對象並將其分配給變量 testObject
。如今對於大多數初學者來講,他們會試着經過將 testObject
分配給新變量來建立這個對象的副本,以便在其代碼中進行操做。很抱歉用這種方法行不通。編碼
下面是一個代碼片斷,說明了爲何不起做用。spa
let testObject = {
a: 1,
b: 2,
c: 3
};
// 爲 testObject 建立一個副本
let testObjectCopy = testObject;
testObject.a = 9;
console.log(testObjectCopy.a);
// 這裏 a = 9
複製代碼
如上面的代碼片斷所示,建立新變量 testObjectCopy
實際上並不建立 testObject
的副本。相反它只是引用 testObject
。你對所謂的副本作的任何更改也將反映在原始對象中。prototype
循環遍歷對象並將每一個屬性複製到新對象也不起做用。
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
屬性是惟一要改變的屬性。
🤓試一試,看看它如何幫助你編碼!🚀