在JavaScript中,解構賦值是一項非常方便的操作。通過解構賦值,我們可以輕鬆地將數組或對象的成員值分配給變量。但是,使用解構賦值時,我們需要了解它所使用的是深拷貝還是淺拷貝的機制。在這篇文章中,我們將從多個方面詳細闡述解構賦值的深拷貝和淺拷貝機制。
一、基礎知識
解構賦值是以“結構”為單位來進行賦值的操作。例如,我們可以使用數組或對象的鍵來將它們的值分配給變量,例如:
“`javascript
const arr = [1, 2, 3];
const [x, y, z] = arr;
console.log(x, y, z); // 1 2 3
“`
“`javascript
const obj = { foo: ‘hello’, bar: ‘world’ };
const {foo, bar} = obj;
console.log(foo, bar); // hello world
“`
解構賦值的核心是綁定。它會把右側的值綁定到左側的變量上。
二、基本類型
在解構賦值中,基本類型是屬於淺拷貝的範疇。具體來說,如果我們使用解構賦值將一個基本類型數據賦給另一個變量,那麼這兩個變量將指向同一個內存地址。例如:
“`javascript
let a = ‘hello’;
let b = a; // 直接複製
console.log(a, b); // hello hello
a = ‘world’;
console.log(a, b); // world hello
“`
在這個例子中,儘管我們改變了變量a的值,但變量b的值仍然是原始的“hello”值。這是因為基本類型的賦值時採用的是值傳遞,這種特性也被延續到了解構賦值中。
可以用下面的代碼對解構賦值的淺拷貝進行證明:
“`javascript
let a = { foo: ‘hello’ };
let b = { …a }; // 通過擴展運算符進行淺拷貝
console.log(a, b); // { foo: ‘hello’ } { foo: ‘hello’ }
a.foo = ‘world’;
console.log(a, b); // { foo: ‘world’ } { foo: ‘hello’ }
“`
在這個例子中,我們使用了擴展運算符進行了一個表面上是完整拷貝的操作,但其實這裡只是進行了淺拷貝。當我們修改變量a的屬性foo時,變量b並沒有跟着修改,因為兩個變量只是引用了同一個對象的地址。
三、引用類型
引用類型是指對象、數組和函數。當我們用解構賦值時,它們屬於深拷貝範疇。例如:
“`javascript
let a = { foo: { bar: ‘hello’ } };
let b = { …a }; // 通過擴展運算符進行淺拷貝
console.log(a, b); // { foo: { bar: ‘hello’ } } { foo: { bar: ‘hello’ } }
a.foo.bar = ‘world’;
console.log(a, b); // { foo: { bar: ‘world’ } } { foo: { bar: ‘hello’ } }
“`
儘管我們使用了擴展運算符進行了淺拷貝,但當我們修改了變量a的屬性時,變量b的引用關係並沒有改變。因此,在JavaScript中,解構賦值對引用類型的賦值採用的是深拷貝。
同時我們可以使用Object.assign()或者JSON.parse()來進行深拷貝的複製操作。例如:
“`javascript
let a = { foo: { bar: ‘hello’ } };
let b = JSON.parse(JSON.stringify(a)); // 通過JSON來進行深拷貝複製
console.log(a, b); // { foo: { bar: ‘hello’ } } { foo: { bar: ‘hello’ } }
a.foo.bar = ‘world’;
console.log(a, b); // { foo: { bar: ‘world’ } } { foo: { bar: ‘hello’ } }
“`
這裡通過JSON來進行深拷貝複製,可以看出深度複製是完整的。修改變量a的屬性foo的子屬性bar時,變量b的值沒有跟着改動。
四、函數參數
在JavaScript中,我們經常將對象作為函數參數進行傳遞。使用解構賦值可以讓代碼更加簡潔易讀。例如:
“`javascript
function foo({ x = 1, y = 2 } = {}) {
console.log(x, y);
}
foo({ x: 3 }); // 3 2
foo(); // 1 2
“`
在這個例子中,我們將解構賦值作為函數的默認參數進行傳遞。通過這樣的方式,我們可以在函數中使用解構賦值,同時也可以不傳遞參數。
需要注意的是,當我們使用默認參數時,如果沒有傳入參數,則會被默認賦值為undefined。這樣,我們可以使用解構賦值的默認值機制來為變量提供一個默認值。例如:
“`javascript
function foo({ x = 1, y = 2 } = { x: 0, y: 0 }) {
console.log(x, y);
}
foo({ x: 3 }); // 3 2
foo(); // 1 2
“`
在這個例子中,我們使用了解構賦值的默認參數,同時為傳遞參數的情況做了處理,使得其默認參數為x: 0, y: 0。
五、數組拼接
在解構賦值中,我們可以使用剩餘運算符來進行數組拼接。例如:
“`javascript
const arr1 = [1, 2, 3];
const arr2 = [4, 5, 6];
const arr = […arr1, …arr2];
console.log(arr); // [1, 2, 3, 4, 5, 6]
“`
當我們使用剩餘運算符時,它所代表的是數組中的其餘元素。由於解構賦值會淺拷貝數組元素,因此我們使用剩餘運算符進行數組拼接時,其實是在創建一個新的數組,而不是在原有的數組上進行操作。
六、小結
在這篇文章中,我們從多個方面詳細闡述了解構賦值的深拷貝和淺拷貝機制。我們了解了基礎知識、基本類型、引用類型、函數參數、數組拼接等內容。通過這樣的介紹,我們可以更好地使用解構賦值,同時避免在編寫代碼的時候出現意想不到的結果。
代碼示例:https://codepen.io/parkouroff/pen/ZELvwvK
原創文章,作者:小藍,如若轉載,請註明出處:https://www.506064.com/zh-hant/n/181643.html