在本章中,我們將學習兩種不同的資料更新方式
後者的方式類似於先建立副本,然後以破壞性更新副本,但它會同時執行這兩個動作。
以下程式碼展示一個以破壞性更新物件屬性的函式,並在一個物件上使用它。
function setPropertyDestructively(obj, key, value) {
obj[key] = value;
return obj;
}
const obj = {city: 'Berlin', country: 'Germany'};
setPropertyDestructively(obj, 'city', 'Munich');
assert.deepEqual(obj, {city: 'Munich', country: 'Germany'});
以下程式碼展示非破壞性更新物件
function setPropertyNonDestructively(obj, key, value) {
const updatedObj = {};
for (const [k, v] of Object.entries(obj)) {
updatedObj[k] = (k === key ? value : v);
}
return updatedObj;
}
const obj = {city: 'Berlin', country: 'Germany'};
const updatedObj = setPropertyNonDestructively(obj, 'city', 'Munich');
// We have created an updated object:
assert.deepEqual(updatedObj, {city: 'Munich', country: 'Germany'});
// But we didn’t change the original:
assert.deepEqual(obj, {city: 'Berlin', country: 'Germany'});
展開運算式讓 setPropertyNonDestructively()
變得更簡潔
setPropertyNonDestructively()
的兩個版本都進行淺層更新:它們只變更物件的最上層。
以下程式碼展示一個以破壞性更新陣列元素的函式,並在一個陣列上使用它。
function setElementDestructively(arr, index, value) {
arr[index] = value;
}
const arr = ['a', 'b', 'c', 'd', 'e'];
setElementDestructively(arr, 2, 'x');
assert.deepEqual(arr, ['a', 'b', 'x', 'd', 'e']);
以下程式碼展示非破壞性更新陣列
function setElementNonDestructively(arr, index, value) {
const updatedArr = [];
for (const [i, v] of arr.entries()) {
updatedArr.push(i === index ? value : v);
}
return updatedArr;
}
const arr = ['a', 'b', 'c', 'd', 'e'];
const updatedArr = setElementNonDestructively(arr, 2, 'x');
assert.deepEqual(updatedArr, ['a', 'b', 'x', 'd', 'e']);
assert.deepEqual(arr, ['a', 'b', 'c', 'd', 'e']);
.slice()
和展開運算式讓 setElementNonDestructively()
變得更簡潔
function setElementNonDestructively(arr, index, value) {
return [
...arr.slice(0, index), value, ...arr.slice(index+1)];
}
setElementNonDestructively()
的兩個版本都進行淺層更新:它們只變更陣列的最上層。
到目前為止,我們僅淺層更新資料。讓我們來處理深度更新。以下程式碼顯示如何手動執行此操作。我們正在變更姓名和雇主。
const original = {name: 'Jane', work: {employer: 'Acme'}};
const updatedOriginal = {
...original,
name: 'John',
work: {
...original.work,
employer: 'Spectre'
},
};
assert.deepEqual(
original, {name: 'Jane', work: {employer: 'Acme'}});
assert.deepEqual(
updatedOriginal, {name: 'John', work: {employer: 'Spectre'}});
以下函式實作一般深度更新。
function deepUpdate(original, keys, value) {
if (keys.length === 0) {
return value;
}
const currentKey = keys[0];
if (Array.isArray(original)) {
return original.map(
(v, index) => index === currentKey
? deepUpdate(v, keys.slice(1), value) // (A)
: v); // (B)
} else if (typeof original === 'object' && original !== null) {
return Object.fromEntries(
Object.entries(original).map(
(keyValuePair) => {
const [k,v] = keyValuePair;
if (k === currentKey) {
return [k, deepUpdate(v, keys.slice(1), value)]; // (C)
} else {
return keyValuePair; // (D)
}
}));
} else {
// Primitive value
return original;
}
}
如果我們將 value 視為我們正在更新的樹狀結構的根,則 deepUpdate() 僅深度變更單一分支(A 行和 C 行)。所有其他分支都淺層複製(B 行和 D 行)。
以下是使用 deepUpdate() 的範例