做者:Angelos Chalaris瘋狂的技術宅javascript
原文:https://www.30secondsofcode.o...前端
未經容許嚴禁轉載java
JavaScript 的原始數據類型(例如number、string、null,undefined 和 boolean)是不可變的,這意味着一旦建立,它們的值就沒法更改。可是對象和數組是可變的,容許在建立後修改其值。實際上,這意味着基元是經過值傳遞的,而對象和數組是經過引用傳遞的。考慮如下例子:程序員
let str = 'Hello'; let copy = str; copy = 'Hi'; // str = 'Hello', copy = 'Hi' let obj = { a: 1, b: 2 }; let objCopy = obj; objCopy.b = 4; // obj = { a: 1, b: 4}, objCopy = { a: 1, b: 4 }
在 obj
中發生的事是該對象是經過引用傳遞給 objCopy
的,所以修改其中一個變量的值也會影響另外一個變量。 objCopy
其實是引用同一對象的別名。咱們能夠使用多種技術(例如,展開運算符(...
)或帶有空對象的 Object.assign()
)來克隆對象,以解決此問題:面試
let obj = { a: 1, b: 2}; let clone = { ...obj }; clone.b = 4; // obj = { a: 1, b: 2}, clone = { a: 1, b: 4 } let otherClone = Object.assign({}, obj); otherClone.b = 6; clone.b = 4; // obj = { a: 1, b: 2}, otherClone = { a: 1, b: 6 }
這兩種解決方案都展現了淺克隆的例子,由於它們適用於外部(淺)對象,可是若是咱們嵌套(深)對象,這些對象最終將經過引用傳遞,從而致使失敗。有幾種方法能夠解決這個問題,其中更簡單的方法是用 JSON.stringify()
和 JSON.parse()
處理:segmentfault
let obj = { a: 1, b: { c: 2 } }; let clone = JSON.parseJSON.stringify(obj)); clone.b.c = 4; // obj = { a: 1, b: { c: 2 }}, clone = { a: 1, b: { c: 4 } }
雖然上面的例子有效,但它必須序列化和反序列化整個對象,這可能會嚴重影響代碼的性能,因此它可能不適用於較大的對象或對性能要求很高的項目。數組
另外,你能夠用遞歸來深度克隆對象,而且速度要快得多,例以下面代碼中的遞歸函數。一樣,若是你想使用現成的淺克隆函數,則能夠這樣作:const shallowClone = obj => Object.assign({}, obj);
。服務器
const deepClone = obj => { if (obj === null) return null; let clone = Object.assign({}, obj); Object.keys(clone).forEach( key => (clone[key] = typeof obj[key] === 'object' ? deepClone(obj[key]) : obj[key]) ); return Array.isArray(obj) && obj.length ? (clone.length = obj.length) && Array.from(clone) : Array.isArray(obj) ? Array.from(obj) : clone; };