我們一起倆聊聊使用 Array.prototype.with 更新不可變數(shù)組
慶祝:此功能現(xiàn)已在所有三個(gè)主要瀏覽器引擎中可用!
瀏覽器最近獲得了一種新的可互操作方法,您可以在數(shù)組上調(diào)用它:Array.prototype.with() 。
Browser Support 瀏覽器支持:
- chrome 110
- Edge 110
- firefox 115
- Safari 16
本文探討了此方法的工作原理以及如何使用它來(lái)更新數(shù)組而不改變?cè)紨?shù)組。
Array.prototype.with(index, value) 簡(jiǎn)介
Array.prototype.with(index, value) 方法返回所調(diào)用的數(shù)組的副本,并將 index 設(shè)置為您提供的新 value 。
以下示例顯示年齡數(shù)組。您想要?jiǎng)?chuàng)建數(shù)組的新副本,同時(shí)將第二個(gè)年齡從 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, …) 替換第二項(xiàng) ( index = 1 )。ages.with(1, 16) 將第二個(gè)項(xiàng)目分配給 16 。
這就是你如何通過(guò)修改來(lái)創(chuàng)建一個(gè)新的數(shù)組副本。
當(dāng)您想要確保原始數(shù)組保持不變時(shí),這非常有用,本文介紹了這方面的一些用例。但是,現(xiàn)在看看如果使用括號(hào)表示法會(huì)發(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 變量。這是因?yàn)楫?dāng)您分配 ages = newAges 時(shí),JavaScript 不會(huì)復(fù)制該數(shù)組,而是創(chuàng)建對(duì)另一個(gè)數(shù)組的引用。因此,其中一個(gè)的任何更改也會(huì)影響另一個(gè),因?yàn)樗鼈兌贾赶蛲粋€(gè)數(shù)組。
Array.prototype.with() 和不變性
不變性是許多前端庫(kù)和框架的核心,僅舉幾例:React(和 redux)和 Vue
此外,其他庫(kù)和框架不一定需要不變性,但鼓勵(lì)它以獲得更好的性能:Angular 和 Lit
因此,開(kāi)發(fā)人員經(jīng)常不得不使用其他返回?cái)?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)下面是一個(gè) Codepen 示例,說(shuō)明了如何在 React 中結(jié)合 useState 使用 .with() 來(lái)永久更新項(xiàng)目數(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() 方法返回?cái)?shù)組的副本,因此您可以鏈接多個(gè) .with() 調(diào)用甚至其他數(shù)組方法。以下示例演示了從數(shù)組中遞增第二個(gè)和第三個(gè)年齡:
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)其他新的不可變方法
其他三種方法最近也實(shí)現(xiàn)了互操作:
- Array.prototype.toReversed() 反轉(zhuǎn)數(shù)組而不改變?cè)紨?shù)組。
- Array.prototype.toSorted() 對(duì)數(shù)組進(jìn)行排序而不改變?cè)紨?shù)組。
- Array.prototype.toSpliced() 其工作方式類似于 .splice() 但不會(huì)改變?cè)紨?shù)組。
根據(jù) MDN 的說(shuō)法,這三種方法是其對(duì)應(yīng)方法的復(fù)制版本。這些方法也可以用在期望或首選不變性的地方。
總之,使用本文介紹的四種方法之一可以在 JavaScript 中更輕松地實(shí)現(xiàn)不可變更新。具體來(lái)說(shuō), .with() 方法可以更輕松地更新數(shù)組的單個(gè)元素,而無(wú)需更改原始數(shù)組。
原文:https://web.developers.google.cn/blog/array-with?hl=en




































