很多人使用 JavaScript 数组时,最多就是 for 循环、map() 或者 filter() 等常见方法,但其实数组还有不少“隐藏招数”。这篇文章介绍的 7 个方法,也许会让你眼前一亮。
1. copyWithin()
想象一下:取走一片披萨,然后又把它塞回披萨盒的另一个角落,这就是 copyWithin() 的感觉。它会将数组中指定范围的元素复制到同一个数组的其他位置,数组长度并不会改变。
const arr = [1, 2, 3, 4, 5];
arr.copyWithin(0, 3); // [4, 5, 3, 4, 5]
在这里,从索引 3 开始的内容 (即 [4, 5]) 被复制到索引 0 的位置,替换了原来的 [1, 2]。也可以再加一个结束索引来限定要复制的范围。
何时使用
- 快速地在数组内部进行重排,而不想新建数组。
- 可以写一些奇妙的“滑动窗口”或排序前的临时处理逻辑。
2. at() 与 with()
这是近几年新增的方法。at() 先出现,可以用负数轻松获取数组末尾元素;然后在 2023 年新增的 with() 则能对数组的某个位置做“不可变替换”——返回一个全新的数组而不改变原数组。
const colors = ['red', 'blue', 'green', 'yellow'];
console.log(colors.at(-1)); // 'yellow'
console.log(colors.with(1, 'purple'));
// ['red', 'purple', 'green', 'yellow']
at(-1) 就是取最后一个元素。with() 可以在索引 1 上替换为 'purple',并返回新数组,非常适合需要保持原数组不变的场景,比如在 Redux 这类数据管理中。
3. reduceRight()
大部分人熟悉 reduce(),它被称为数组方法里的“瑞士军刀”,可以实现各种聚合操作。不过,想反向迭代数组怎么办?那就是 reduceRight()。
const arr = ['a', 'b', 'c', 'd'];
const result = arr.reduceRight((acc, curr) => acc + curr);
console.log(result); // 'dcba'
和 reduce() 不同之处在于,它从数组末尾往前处理元素。这对于需要反向拼接字符串或逆序计算的场景特别有用。
4. findLast()
findLast() 是 ES13(2022)中的新成员,和 find() 类似,但搜索方向相反,它会从数组的末尾开始查找。
const nums = [1, 2, 3, 4, 5, 6, 7];
console.log(nums.findLast(n => n % 2 === 0)); // 6
当你知道需要查找的元素更可能出现在数组后半部分时,findLast() 就很便捷,避免做无意义的前段搜索。
5. toSorted(), toReversed(), toSpliced()
这是 ES2023 里为数组新增的“不变(immutable)”版本,功能对应老牌的 sort(), reverse(), splice(),但它们不会修改原数组,会返回一个新数组。
const arr = [3, 1, 4, 1, 5];
// 不影响原数组的排序
console.log(arr.toSorted()); // [1, 1, 3, 4, 5]
console.log(arr); // [3, 1, 4, 1, 5]
// 不影响原数组的反转
console.log(arr.toReversed()); // [5, 1, 4, 1, 3]
console.log(arr); // [3, 1, 4, 1, 5]
对于喜欢函数式编程、或在项目中需要维持状态不可变的场景,这些方法能避免“写着写着,原数组就被改掉了”的坑,提高可维护性。
6. lastIndexOf()
比 indexOf() 更少被提及的是 lastIndexOf(),它能找到指定元素最后一次出现的位置,还可以指定搜索的起始点。
const arr = ['apple', 'banana', 'cherry', 'apple'];
console.log(arr.lastIndexOf('apple')); // 3
console.log(arr.lastIndexOf('apple', 2)); // 0
当数组里有重复元素、你又需要从后往前找的时候,lastIndexOf() 就格外顺手。
7. flatMap()
这是将 map() 和 flat() 合二为一的方法。它会对每个元素执行映射,然后把结果拍平一层。
const arr = [1, 2, [3], 4];
console.log(arr.flatMap(x => [x * 2])); // [2, 4, 6, 8]
这样就不用先 map() 再 flat(),一次搞定,代码更简洁。
一点额外想法
这些数组方法知名度不如 push()、filter() 那么高,但都很有用。合理运用它们可以让代码更加优雅,也能降低一些常见的 Bug 风险。
在团队合作中,适度使用这些相对“小众”的方法还能让同事们眼前一亮,当然别忘了写好注释,让大家都能读懂你的代码。
小技巧
- 在需要“从末尾取元素”或“只更新数组某个位置但保持不可变”时,直接用 at() / with() 就能省不少功夫。
- 在操作复杂数据时,尝试使用 toSorted()、toReversed() 等不可变方法,可以避免状态被意外改写。
- 如果想让代码逻辑更直观,可以把 reduceRight() 和 flatMap() 同时用起来,一边翻转一边拍平,能得到很多创造性玩法。
记住这句话:对数组的掌控,不止于 for 和 map(),这些鲜为人知的方法同样值得尝试。祝编码愉快!