使用 Array.prototype.with 的不可變更陣列更新

瀏覽器最近新增了可互通的方法,您可以在陣列上呼叫該方法: Array.prototype.with()

Browser Support

  • Chrome: 110.
  • Edge: 110.
  • Firefox: 115.
  • Safari: 16.

Source

本文將探討這個方法如何運作,以及如何使用這個方法更新陣列,而不變動原始陣列。

藝人專用Array.prototype.with(index, value)

Array.prototype.with(index, value) 方法會傳回所呼叫陣列的副本,並將 index 設為您提供的新 value

以下範例顯示年齡陣列。您想要建立陣列的新副本,同時將第二個年齡從 15 變更為 16:

const ages = [10, 15, 20, 25];

const newAges = ages.with(1, 16);
console.log(newAges); // [10, 16, 20, 25]
console.log(ages); // [10, 15, 20, 25] (unchanged)

程式碼細目:ages.with(...) 會傳回 ages 變數的副本,而不會修改原始陣列。ages.with(1, …) 會取代第二個項目 (index = 1)。ages.with(1, 16) 會將第二個項目指派給 16

這樣您就能建立經過修改的陣列副本。

如要確保原始陣列維持不變,這項功能就非常實用。本文將介紹這項功能的部分用途。但現在,請看看使用方括號標記會發生什麼情況:

const ages = [10, 15, 20, 25];

const newAges = ages;
newAges[1] = 16;
console.log(newAges); // [10, 16, 20, 25]
console.log(ages); // [10, 16, 20, 25] (Also changed 🙁)

如您所見,這個範例中的 ages 變數也經過修改。這是因為指派 ages = newAges 時,JavaScript 不會複製陣列,而是建立對其他陣列的參照。因此,如果變更其中一個陣列,另一個陣列也會受到影響,因為兩者都指向同一個陣列。

Array.prototype.with() 和不變性

許多前端程式庫和架構的核心都是不可變性,例如 React (和 Redux) 和 Vue

此外,其他程式庫和架構不一定需要不可變動性,但為了提升效能,建議採用這項做法:Angular 和 Lit

因此開發人員通常必須使用其他方法傳回陣列副本,這會犧牲程式碼可讀性:

const ages = [10, 15, 20, 25];

const newAges = ages.map((age, index) => {
    if (index === 1) {
         return 16;
    }
    return age;
});

console.log(newAges); // [10, 16, 20, 25]
console.log(ages); // [10, 15, 20, 25] (Remains unchanged)

以下是 Codepen 範例,說明如何在 React 中搭配 useState 使用 .with(),以不可變動的方式更新項目陣列:

由於 .with() 方法會傳回陣列副本,因此您可以串連多個 .with() 呼叫,甚至是其他陣列方法。以下範例示範如何遞增陣列中的第二和第三個年齡:

const ages = [10, 15, 20, 25];

const newAges = ages.with(1, ages[1] + 1).with(2, ages[2] + 1)

console.log(newAges); // [10, 16, 21, 25]
console.log(ages); // [10, 15, 20, 25] (unchanged)

其他新的不可變動方法

最近有三種其他方法也開始支援互通性:

根據 MDN,這三種方法是相應方法的複製版本。在預期或偏好不可變動性的情況下,也可以使用這些方法。

總而言之,您可以使用本文介紹的四種方法,在 JavaScript 中更輕鬆地完成不可變動的更新。具體來說,.with() 方法可讓您更輕鬆地更新陣列的單一元素,而不必變動原始陣列。