一些新的数组不可变方法

984 阅读3分钟

前言

数组是最常用的 JavaScript 数据结构之一。相信你对它的使用是很熟悉的,数组提供了很多有用的方法,其中有些是不可变方法,有些是可变方法。

是否为可变方法取决于方法调用后会不会改变原数组,可变方法会改变原始数组,不可变则不会。

可变方法有:

  • push:向数组的末尾添加一个或更多元素,并返回新的长度。
  • pop:删除数组的最后一个元素并返回删除的元素。
  • sort:对数组的元素进行排序。
  • splice:从数组中添加或删除元素。
  • reverse:反转数组的元素顺序。
  • ...

不可变方法有:

  • concat:连接两个或更多的数组,并返回结果。
  • map: 通过指定函数处理数组的每个元素,并返回处理后的数组。
  • reduce:将数组元素计算为一个值(从左到右)。
  • every: 检测数值元素的每个元素是否都符合条件。
  • ...

不可变性(Immutability)是许多前端库的核心,如:redux,也是函数式编程的核心原理,不可变性有助于减少代码中的副作用,使代码更易于维护和测试。

接下来介绍一些新的数组不可变方法,让你能更好使用数组进行开发。

方法介绍

with

Array.prototype.with(index, value) 方法会返回对其调用的数组的副本,并将 index 设置为您提供的新 value。

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)

需要注意的是,返回的新数组是相当于做了个浅复制后再替换值。

const arr1 = [{ a: 1 }, { b: 2 }];
const arr2 = arr1.with(0, { c: 3 })

console.log(arr1) // [{ a: 1 }, { b: 2 }]
console.log(arr2) // [{ c: 3 }, { b: 2 }]

arr1[1].b = 4
console.log(arr2[1].b) // 4

toReversed

Array.prototype.toReversed() 这个方法用法和 reverse() 基本相同,就是 toReversed() 会返回一个新的数组,而不是在原数组上进行反转。

const items = [1, 2, 3];
console.log(items); // [1, 2, 3]

const reversedItems = items.toReversed();
console.log(reversedItems); // [3, 2, 1]
console.log(items); // [1, 2, 3]

toSorted

同样的 Array.prototype.toSorted() 方法的用法和 sort() 一样,就是 toSorted 是返回新数组。

const values = [1, 10, 21, 2];
const sortedValues = values.toSorted((a, b) => a - b);
console.log(sortedValues); // [1, 2, 10, 21]
console.log(values); // [1, 10, 21, 2]

toSpliced

splice() 方法也是数组中常用的方法之一,而 Array.prototype.toSpliced() 则是它的不可变版本,即会返回一个新数组。

const months = ["Jan", "Mar", "Apr", "May"];

// 在索引 1 处添加一个元素
const months2 = months.toSpliced(1, 0, "Feb");
console.log(months2); // ["Jan", "Feb", "Mar", "Apr", "May"]

// 从第 2 个索引开始删除两个元素
const months3 = months2.toSpliced(2, 2);
console.log(months3); // ["Jan", "Feb", "May"]

// 在索引 1 处用两个新元素替换一个元素
const months4 = months3.toSpliced(1, 1, "Feb", "Mar");
console.log(months4); // ["Jan", "Feb", "Mar", "May"]

// 原数组不会被修改
console.log(months); // ["Jan", "Mar", "Apr", "May"]

总结

值的注意的是,上面几个方法都是浅复制。如果你想更好地执行不可变性编程,你可以试着使用 immer、mutative 之类的库来开发。