一、參數對象為基本數據類型時
在調用object.assign()時,如果傳入的參數對象為基本數據類型(number、string、boolean、null、undefined、NaN),則是淺拷貝。例如:
let obj1 = {a: 1, b: {c: 2}};
let obj2 = Object.assign({}, obj1);
obj1.b.c = 3;
console.log(obj2.b.c); // output: 3
上面的例子中,我們先定義了一個包含基本類型和對象類型的對象obj1,然後用object.assign()將obj1淺拷貝到一個空對象中。接着,我們改變了obj1中嵌套對象b的屬性c的值,輸出obj2中對應的屬性c的值,發現也被改變了。
由此可以看出,因為obj1和obj2中的嵌套對象是同一個引用,所以改變一個也會影響其他的。
二、參數對象中有嵌套對象或數組
如果參數對象中有嵌套的對象或數組,那麼使用object.assign()時會出現淺拷貝的情況。例如:
let obj1 = {a: 1, b: {c: 2}};
let obj2 = Object.assign({}, obj1);
obj1.b.d = [3, 4];
console.log(obj2.b.d); // output: [3, 4]
上面的例子中,我們先定義了一個包含基本類型和嵌套對象的對象obj1,然後用object.assign()將obj1淺拷貝到一個空對象中。接着,我們改變了obj1中嵌套對象b的屬性d的值,輸出obj2中對應的屬性d的值,發現也被改變了。
由此可以看出,引用類型的賦值實際上是將指針複製一份,指向同一個地址,因此改變其中一個對象的嵌套屬性或數組將會影響到另一個對象。
三、深拷貝的實現方法
在實際應用中,如果我們需要對嵌套對象或數組進行拷貝,需要使用深拷貝的方式。下面介紹幾種常見的深拷貝實現方法:
1. JSON.parse()和JSON.stringify()
這是最常見的一種深拷貝方法,基於JSON.parse()解析字符串以及JSON.stringify()將對象轉為字符串的特性,實現嵌套對象或數組的深拷貝。例如:
let obj1 = {a: 1, b: {c: 2}};
let obj2 = JSON.parse(JSON.stringify(obj1));
obj1.b.c = 3;
console.log(obj2.b.c); // output: 2
上面的例子中,我們先定義了一個包含基本類型和嵌套對象的對象obj1,然後使用JSON.parse()和JSON.stringify()對其進行深拷貝。接着,我們改變了obj1中嵌套對象b的屬性c的值,輸出obj2中對應的屬性c的值,發現沒有被改變。
但是需要注意的是,這種方法有以下缺點:
- 只能處理JS支持的數據類型,即不能處理RegExp、Date實例、函數等非JSON數據類型。
- 忽略undefined和Symbol類型的屬性。
- 不能實現循環引用的深拷貝,否則會拋出錯誤。
2. 遞歸拷貝
遞歸拷貝是指遍歷對象或數組,對其中的嵌套對象或數組使用深拷貝的方式逐一拷貝,最終實現完全複製。例如:
function deepCopy(obj) {
if(typeof obj !== 'object') {
return obj;
}
let newObj = Array.isArray(obj) ? [] : {};
for(let i in obj) {
newObj[i] = deepCopy(obj[i]);
}
return newObj;
}
let obj1 = {a: 1, b: {c: 2}};
let obj2 = deepCopy(obj1);
obj1.b.c = 3;
console.log(obj2.b.c); // output: 2
上面的例子中,我們先定義了一個包含基本類型和嵌套對象的對象obj1,然後使用遞歸拷貝函數deepCopy()對其進行深拷貝。接着,我們改變了obj1中嵌套對象b的屬性c的值,輸出obj2中對應的屬性c的值,發現沒有被改變。
遞歸拷貝的好處是可以完全複製對象、數組以及其中包含的各種數據類型,沒有限制,但是由於遞歸過程中會創建大量的對象或數組,因此如果拷貝的對象比較大或嵌套層數較深時,可能會影響性能。
3. Lodash的_.cloneDeep()
Lodash是一個實用的JS工具庫,提供了豐富的函數,包括深拷貝的函數_.cloneDeep()。該函數可以對任何數據類型進行深拷貝,支持循環引用的拷貝,是比較常用的深拷貝方法之一。例如:
const _ = require('lodash');
let obj1 = {a: 1, b: {c: 2}};
let obj2 = _.cloneDeep(obj1);
obj1.b.c = 3;
console.log(obj2.b.c); // output: 2
上面的例子中,我們先定義了一個包含基本類型和嵌套對象的對象obj1,然後使用Lodash的_.cloneDeep()對其進行深拷貝。接着,我們改變了obj1中嵌套對象b的屬性c的值,輸出obj2中對應的屬性c的值,發現沒有被改變。
需要注意的是,使用Lodash需要先安裝Lodash庫,在Node.js中使用方式例如上面的代碼。
原創文章,作者:小藍,如若轉載,請註明出處:https://www.506064.com/zh-hant/n/297469.html