JS `Change Array by Copy` (提案):`toSorted`, `toReversed`, `toSpliced`

各位观众,老铁们,晚上好!今天咱们来聊聊JavaScript里数组的“复制粘贴大法”,啊不,是“Change Array by Copy”提案,也就是 toSorted, toReversed, toSpliced 这些新玩意儿。 这玩意儿,能让你不动声色地“改动”数组,实际上返回的是一个全新的数组,妈妈再也不用担心我污染原始数组了!

开场白:数组的那些“爱恨情仇”

话说JavaScript里的数组,那可是个磨人的小妖精。你改它吧,一不小心全局受影响,原始数据也被污染了;你不改它吧,很多时候需求又必须得改。 这就好像谈恋爱,既想保持自我,又想和对方更亲密。

以前我们怎么解决这个问题呢? 深拷贝! 各种奇技淫巧,什么JSON.parse(JSON.stringify(arr)),什么手写递归拷贝,写起来麻烦不说,性能还不见得好。

现在好了,有了这几个 “to” 开头的函数,我们就可以优雅地、安全地、放心地修改数组的副本了。 就像拥有了无限复活币,随便你怎么折腾,原始数组毫发无损。

主角登场:toSorted() – 排序新姿势

先说说 toSorted()。 顾名思义,它是用来排序的。 以前我们用 sort() 方法,会直接修改原始数组。 这就好像你把家里客厅里的东西重新摆放了一下,客人来了发现客厅格局都变了。

toSorted() 就不一样了,它会返回一个排序后的新数组,原始数组保持不变。 这就好像你把客厅的东西复制了一份到隔壁房间,重新摆放,客人来了还是原来的客厅,而你可以在隔壁房间尽情发挥你的创造力。

const arr = [5, 2, 8, 1, 4];
const sortedArr = arr.toSorted();

console.log("原始数组:", arr); // [5, 2, 8, 1, 4]
console.log("排序后的新数组:", sortedArr); // [1, 2, 4, 5, 8]

看到没? arr 压根没变! sortedArr 才是排序后的结果。

toSorted() 还可以接受一个可选的比较函数,和 sort() 一样。 比如我们要降序排序:

const arr = [5, 2, 8, 1, 4];
const sortedArr = arr.toSorted((a, b) => b - a);

console.log("降序排序后的新数组:", sortedArr); // [8, 5, 4, 2, 1]

主角二号:toReversed() – 反转也优雅

接下来是 toReversed()。 这个方法的作用是反转数组。 以前我们用 reverse() 方法,也是直接修改原始数组。 这就好像你把一本书从头翻到尾,结果这本书的页码顺序都乱了。

toReversed() 就不一样了,它会返回一个反转后的新数组,原始数组保持不变。 这就好像你把这本书复印了一份,然后把复印件从头翻到尾,原书的页码顺序还是好好的。

const arr = [1, 2, 3, 4, 5];
const reversedArr = arr.toReversed();

console.log("原始数组:", arr); // [1, 2, 3, 4, 5]
console.log("反转后的新数组:", reversedArr); // [5, 4, 3, 2, 1]

主角三号:toSpliced() – 切割的艺术

重头戏来了! toSpliced() 这个方法的功能最强大,也最复杂。 它相当于 splice() 方法的“复制版”。 splice() 方法可以删除、替换、添加数组元素,但是会直接修改原始数组。 这就好像你用手术刀给一个人做手术,虽然治好了病,但也留下了伤疤。

toSpliced() 就不一样了,它会返回一个修改后的新数组,原始数组保持不变。 这就好像你用虚拟现实技术给一个人做手术,治好了病,却没有留下任何痕迹。

toSpliced() 的用法和 splice() 非常相似, 它可以接受多个参数:

  • start: 开始修改的索引。
  • deleteCount: 要删除的元素个数。
  • ...items: 要添加的元素。

举几个例子:

  • 删除元素:
const arr = [1, 2, 3, 4, 5];
const splicedArr = arr.toSpliced(2, 1); // 从索引2开始删除1个元素

console.log("原始数组:", arr); // [1, 2, 3, 4, 5]
console.log("修改后的新数组:", splicedArr); // [1, 2, 4, 5]
  • 替换元素:
const arr = [1, 2, 3, 4, 5];
const splicedArr = arr.toSpliced(2, 1, 6); // 从索引2开始删除1个元素,并添加元素6

console.log("原始数组:", arr); // [1, 2, 3, 4, 5]
console.log("修改后的新数组:", splicedArr); // [1, 2, 6, 4, 5]
  • 添加元素:
const arr = [1, 2, 3, 4, 5];
const splicedArr = arr.toSpliced(2, 0, 6, 7); // 从索引2开始删除0个元素,并添加元素6和7

console.log("原始数组:", arr); // [1, 2, 3, 4, 5]
console.log("修改后的新数组:", splicedArr); // [1, 2, 6, 7, 3, 4, 5]

如果 start 是负数,则从数组末尾开始计算索引。 例如,-1 表示数组的最后一个元素,-2 表示倒数第二个元素,以此类推。

const arr = [1, 2, 3, 4, 5];
const splicedArr = arr.toSpliced(-1, 1); // 从倒数第一个元素开始删除1个元素

console.log("原始数组:", arr); // [1, 2, 3, 4, 5]
console.log("修改后的新数组:", splicedArr); // [1, 2, 3, 4]

如果 deleteCount 大于数组的长度减去 start,则会删除从 start 开始到数组末尾的所有元素。

const arr = [1, 2, 3, 4, 5];
const splicedArr = arr.toSpliced(2, 10); // 从索引2开始删除10个元素 (实际上只删除了3, 4, 5)

console.log("原始数组:", arr); // [1, 2, 3, 4, 5]
console.log("修改后的新数组:", splicedArr); // [1, 2]

表格总结:新老方法大PK

为了让大家更清晰地了解这几个新方法和老方法的区别,我做了一个表格:

方法名 是否修改原始数组 返回值 用途
sort() 排序后的原始数组 对数组进行排序
toSorted() 排序后的新数组 对数组进行排序,不修改原始数组
reverse() 反转后的原始数组 反转数组
toReversed() 反转后的新数组 反转数组,不修改原始数组
splice() 包含删除元素的数组 删除、替换、添加数组元素
toSpliced() 修改后的新数组 删除、替换、添加数组元素,不修改原始数组

兼容性:能不能用?

虽然这些方法很香,但是也要考虑兼容性问题。 目前,大部分现代浏览器都已经支持这些方法了,但是对于一些老旧的浏览器,可能还需要使用 Polyfill。 你可以使用 core-js 这个库来提供 Polyfill。

使用场景:哪些地方能用到?

这些方法在很多场景下都非常有用, 比如:

  • React/Vue 等框架的状态管理: 在 Redux、Vuex 等状态管理库中,通常需要保证数据的不可变性。 使用这些方法可以方便地创建新的状态,而不会修改原始状态。
  • 数据可视化: 在数据可视化中,经常需要对数据进行排序、过滤、转换等操作。 使用这些方法可以避免修改原始数据,保证数据的完整性。
  • 函数式编程: 函数式编程强调函数的纯粹性,即函数不应该有副作用。 使用这些方法可以方便地编写纯函数,避免修改外部状态。
  • 需要避免修改原始数组的任何场景: 只要你不想修改原始数组,就可以使用这些方法。

进阶用法:链式调用

由于这些方法都返回一个新的数组,因此可以进行链式调用,让代码更简洁、更易读。

const arr = [5, 2, 8, 1, 4];
const result = arr
  .toSorted()       // 先排序
  .toReversed()     // 再反转
  .toSpliced(1, 1); // 然后删除一个元素

console.log("最终结果:", result); // [5, 4, 2, 1]

注意事项:性能考量

虽然这些方法很方便,但是也要注意性能问题。 因为每次调用这些方法都会创建一个新的数组,所以如果对大型数组进行频繁的操作,可能会影响性能。

因此,在性能敏感的场景下,需要仔细权衡是否使用这些方法。 如果性能要求很高,可以考虑使用一些优化的算法,或者直接修改原始数组。

总结:拥抱新特性,提升开发效率

总的来说,toSorted, toReversed, toSpliced 这几个新方法,是 JavaScript 数组操作的一大利器。 它们可以帮助我们更安全、更优雅地修改数组,避免污染原始数据,提升开发效率。 虽然需要注意兼容性和性能问题,但是瑕不掩瑜,建议大家尽快学习和使用这些新特性。

好了,今天的分享就到这里。 希望大家有所收获! 如果有什么疑问,欢迎在评论区留言。 咱们下期再见!

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注