我們一起倆聊聊使用 Array.prototype.with 更新不可變數(shù)組
慶祝:此功能現(xiàn)已在所有三個主要瀏覽器引擎中可用!
瀏覽器最近獲得了一種新的可互操作方法,您可以在數(shù)組上調(diào)用它:Array.prototype.with() 。
Browser Support 瀏覽器支持:
- chrome 110
- Edge 110
- firefox 115
- Safari 16
本文探討了此方法的工作原理以及如何使用它來更新數(shù)組而不改變原始數(shù)組。
Array.prototype.with(index, value) 簡介
Array.prototype.with(index, value) 方法返回所調(diào)用的數(shù)組的副本,并將 index 設置為您提供的新 value 。
以下示例顯示年齡數(shù)組。您想要創(chuàng)建數(shù)組的新副本,同時將第二個年齡從 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 變量的副本,而不修改原始數(shù)組。ages.with(1, …) 替換第二項 ( index = 1 )。ages.with(1, 16) 將第二個項目分配給 16 。
這就是你如何通過修改來創(chuàng)建一個新的數(shù)組副本。
當您想要確保原始數(shù)組保持不變時,這非常有用,本文介紹了這方面的一些用例。但是,現(xiàn)在看看如果使用括號表示法會發(fā)生什么:
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 不會復制該數(shù)組,而是創(chuàng)建對另一個數(shù)組的引用。因此,其中一個的任何更改也會影響另一個,因為它們都指向同一個數(shù)組。
Array.prototype.with() 和不變性
不變性是許多前端庫和框架的核心,僅舉幾例:React(和 redux)和 Vue
此外,其他庫和框架不一定需要不變性,但鼓勵它以獲得更好的性能:Angular 和 Lit
因此,開發(fā)人員經(jīng)常不得不使用其他返回數(shù)組副本的方法,從而犧牲了代碼的可讀性:
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 中結(jié)合 useState 使用 .with() 來永久更新項目數(shù)組:
import React, {useState} from 'https://esm.sh/react@18.2.0'
import ReactDOM from 'https://esm.sh/react-dom@18.2.0'
function App() {
const [items, setItems] = useState(["Item 1", "Item 2", "Item 3"]);
const updateItem = (index) => {
// Immutable update
setItems(items.with(index, `Updated item ${index + 1}`));
};
return (
<ul>
{items.map((item, index) => (
<li key={index} className="item">
<button onClick={() => updateItem(index)}>Update</button>
<span>{item}</span>
</li>
))}
</ul>
);
}
ReactDOM.render(<App />,
document.getElementById("root"))
由于 .with() 方法返回數(shù)組的副本,因此您可以鏈接多個 .with() 調(diào)用甚至其他數(shù)組方法。以下示例演示了從數(shù)組中遞增第二個和第三個年齡:
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)
其他新的不可變方法
其他三種方法最近也實現(xiàn)了互操作:
- Array.prototype.toReversed() 反轉(zhuǎn)數(shù)組而不改變原始數(shù)組。
- Array.prototype.toSorted() 對數(shù)組進行排序而不改變原始數(shù)組。
- Array.prototype.toSpliced() 其工作方式類似于 .splice() 但不會改變原始數(shù)組。
根據(jù) MDN 的說法,這三種方法是其對應方法的復制版本。這些方法也可以用在期望或首選不變性的地方。
總之,使用本文介紹的四種方法之一可以在 JavaScript 中更輕松地實現(xiàn)不可變更新。具體來說, .with() 方法可以更輕松地更新數(shù)組的單個元素,而無需更改原始數(shù)組。
原文:https://web.developers.google.cn/blog/array-with?hl=en