在前端开发中,JavaScript 数组是使用频率极高的数据结构。掌握数组的各种方法不仅能提升开发效率,还能避免因误用而导致的 bug。本文将系统性地梳理常用数组方法,重点说明每个方法是否会修改原数组以及返回什么类型的值,并辅以清晰示例,助你彻底掌握数组操作。
📌 分类说明
我们将数组方法分为两大类:
- 会改变原数组的方法(Mutating Methods)
- 不会改变原数组的方法(Non-Mutating / Pure Methods)
⚠️ 注意:有些方法虽然不改变原数组,但若数组元素是引用类型(如对象、数组),其内部属性仍可能被修改。
🔁 一、会改变原数组的方法(Mutating)
1.push()
- 作用:向数组末尾添加一个或多个元素
- 返回值:新数组的长度(
number) - 是否改变原数组:✅ 是
let arr = [1, 2]; let len = arr.push(3, 4); console.log(arr); // [1, 2, 3, 4] console.log(len); // 42.pop()
- 作用:删除数组最后一个元素
- 返回值:被删除的元素(若数组为空则返回
undefined) - 是否改变原数组:✅ 是
let arr = [1, 2, 3]; let last = arr.pop(); console.log(arr); // [1, 2] console.log(last); // 33.shift()
- 作用:删除数组第一个元素
- 返回值:被删除的元素(空数组返回
undefined) - 是否改变原数组:✅ 是
let arr = [1, 2, 3]; let first = arr.shift(); console.log(arr); // [2, 3] console.log(first); // 14.unshift()
- 作用:在数组开头添加一个或多个元素
- 返回值:新数组的长度
- 是否改变原数组:✅ 是
let arr = [2, 3]; let len = arr.unshift(0, 1); console.log(arr); // [0, 1, 2, 3] console.log(len); // 45.splice(start, deleteCount, ...items)
- 作用:从指定位置删除/替换/添加元素
- 返回值:被删除的元素组成的数组(若未删除则返回空数组)
- 是否改变原数组:✅ 是
let arr = [1, 2, 3, 4]; let removed = arr.splice(1, 2, 'a', 'b'); console.log(arr); // [1, 'a', 'b', 4] console.log(removed); // [2, 3]6.reverse()
- 作用:反转数组元素顺序
- 返回值:反转后的数组(注意:是原数组的引用)
- 是否改变原数组:✅ 是
let arr = [1, 2, 3]; let reversed = arr.reverse(); console.log(arr); // [3, 2, 1] console.log(reversed); // [3, 2, 1] — 与 arr 指向同一数组7.sort([compareFunction])
- 作用:对数组元素进行排序(默认按字符串 Unicode 码)
- 返回值:排序后的数组(原数组的引用)
- 是否改变原数组:✅ 是
let arr = [3, 1, 2]; arr.sort((a, b) => a - b); console.log(arr); // [1, 2, 3]💡 提示:若要不改变原数组排序,请先用
slice()或[...arr]复制一份再排序。
8.fill(value, start, end)
- 作用:用指定值填充数组某段区间
- 返回值:被填充后的数组(原数组引用)
- 是否改变原数组:✅ 是
let arr = [1, 2, 3, 4]; arr.fill(0, 1, 3); console.log(arr); // [1, 0, 0, 4]9.copyWithin(target, start, end)
- 作用:浅复制数组的一部分到同一数组的其他位置
- 返回值:修改后的数组(原数组引用)
- 是否改变原数组:✅ 是
let arr = [1, 2, 3, 4, 5]; arr.copyWithin(0, 3, 5); // 将索引3~4的元素复制到开头 console.log(arr); // [4, 5, 3, 4, 5]🧼 二、不会改变原数组的方法(Non-Mutating)
1.concat(...arrays)
- 作用:合并两个或多个数组
- 返回值:新数组
- 是否改变原数组:❌ 否
let arr1 = [1, 2]; let arr2 = [3, 4]; let newArr = arr1.concat(arr2); console.log(arr1); // [1, 2](不变) console.log(newArr); // [1, 2, 3, 4]✅ 推荐使用扩展运算符替代:
[...arr1, ...arr2]
2.slice(start, end)
- 作用:提取数组片段
- 返回值:新数组(浅拷贝)
- 是否改变原数组:❌ 否
let arr = [1, 2, 3, 4]; let part = arr.slice(1, 3); console.log(arr); // [1, 2, 3, 4](不变) console.log(part); // [2, 3]3.map(callback)
- 作用:对每个元素调用函数,生成新数组
- 返回值:转换后的新数组
- 是否改变原数组:❌ 否
let arr = [1, 2, 3]; let doubled = arr.map(x => x * 2); console.log(arr); // [1, 2, 3](不变) console.log(doubled); // [2, 4, 6]4.filter(callback)
- 作用:筛选满足条件的元素
- 返回值:新数组
- 是否改变原数组:❌ 否
let arr = [1, 2, 3, 4]; let evens = arr.filter(x => x % 2 === 0); console.log(arr); // [1, 2, 3, 4](不变) console.log(evens); // [2, 4]5.reduce(callback, initialValue)
- 作用:累积计算,归并为单个值
- 返回值:累积结果(类型由回调决定)
- 是否改变原数组:❌ 否
let arr = [1, 2, 3]; let sum = arr.reduce((acc, val) => acc + val, 0); console.log(arr); // [1, 2, 3](不变) console.log(sum); // 66.find(callback)
- 作用:查找第一个满足条件的元素
- 返回值:找到的元素(未找到返回
undefined) - 是否改变原数组:❌ 否
let arr = [{id: 1}, {id: 2}]; let item = arr.find(x => x.id === 2); console.log(item); // {id: 2}7.findIndex(callback)
- 作用:查找第一个满足条件的元素索引
- 返回值:索引(未找到返回
-1) - 是否改变原数组:❌ 否
8.every(callback)/some(callback)
- 作用:判断所有/部分元素是否满足条件
- 返回值:
boolean - 是否改变原数组:❌ 否
[1, 2, 3].every(x => x > 0); // true [1, 2, 3].some(x => x > 2); // true9.includes(value, fromIndex)
- 作用:判断数组是否包含某值
- 返回值:
boolean - 是否改变原数组:❌ 否
10.indexOf(value)/lastIndexOf(value)
- 作用:查找元素首次/最后一次出现的索引
- 返回值:索引(未找到返回
-1) - 是否改变原数组:❌ 否
11.join(separator)
- 作用:将数组转为字符串
- 返回值:字符串
- 是否改变原数组:❌ 否
['a', 'b', 'c'].join('-'); // "a-b-c"12.flat(depth)
- 作用:扁平化嵌套数组
- 返回值:新数组
- 是否改变原数组:❌ 否
[[1, 2], [3, [4]]].flat(2); // [1, 2, 3, 4]13.flatMap(callback)
- 作用:先 map 再 flat(深度为1)
- 返回值:新数组
- 是否改变原数组:❌ 否
['a b', 'c d'].flatMap(s => s.split(' ')); // ['a', 'b', 'c', 'd']📊 总结表格
| 方法 | 是否改变原数组 | 返回值类型 |
|---|---|---|
push/pop/shift/unshift | ✅ | number(长度)或元素 |
splice | ✅ | 被删除元素组成的数组 |
reverse/sort/fill/copyWithin | ✅ | 原数组引用 |
concat/slice/map/filter/flat/flatMap | ❌ | 新数组 |
reduce/find/findIndex | ❌ | 累积值 / 元素 / 索引 |
every/some/includes | ❌ | boolean |
join | ❌ | string |
indexOf/lastIndexOf | ❌ | number |
✅ 最佳实践建议
- 优先使用不可变方法(如
map,filter),便于调试和状态管理(尤其在 React/Vue 中)。 - 若需修改原数组,明确意图;否则使用
[...arr]或arr.slice()创建副本后再操作。 - 对于排序,避免直接
arr.sort(),推荐:const sorted = [...arr].sort((a, b) => a - b);
📚 结语
掌握数组方法的“副作用”(是否改变原数组)是写出健壮前端代码的关键。希望本文能成为你日常开发的速查手册。欢迎收藏、点赞、评论交流!