很多人使用 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()
,这些鲜为人知的方法同样值得尝试。祝编码愉快!
该文章在 2025/1/16 12:22:49 编辑过