大家好,今天我们来聊一个前端开发中天天打交道的“老朋友”——JavaScript数组。数组作为最基础的数据结构之一,在实际开发中无处不在。无论是处理用户列表、商品数据,还是做复杂的状态管理,都离不开它。
而JS为数组提供了丰富的方法,掌握这些方法不仅能提升编码效率,还能写出更优雅、更易维护的代码。今天我们就来系统地梳理一下数组的常用操作方法,按 增、删、改、查、遍历 五大类来分类讲解,保证你看完后对数组有更全面的理解!
✅ 一、怎么往数组里“加”东西?—— 增(Add)
1. push():尾部添加
最常用的添加方法,在数组末尾添加一个或多个元素,并返回新长度。
const arr = [1, 2];
arr.push(3, 4); // [1, 2, 3, 4]
✅ 特点:改变原数组,返回的是新长度,不是新数组。
2. unshift():头部添加
和 push 相反,在数组开头插入元素。
const arr = [2, 3];
arr.unshift(1); // [1, 2, 3]
⚠️ 注意:unshift 会重新索引整个数组,性能比 push 差,尤其数组大时慎用。
3. splice(start, deleteCount, ...items):万能插入/删除
这是一个“瑞士军刀”级的方法,既能删也能增。要实现“插入”,只需设置 deleteCount 为 0。
const arr = [1, 4];
arr.splice(1, 0, 2, 3); // 在索引1处插入2和3
// arr 变成 [1, 2, 3, 4]
✅ 灵活强大,但稍复杂,适合精确控制插入位置。
4. concat():拼接出新数组
如果你不想修改原数组,想生成一个新数组,concat 就派上用场了。
const arr1 = [1, 2];
const arr2 = [3, 4];
const newArr = arr1.concat(arr2); // [1, 2, 3, 4]
✅ 返回新数组,不改变原数组,适合函数式编程。
5. Array.of() 和 Array.from():创建新数组
虽然不是直接“添加”,但它们是创建数组的好帮手:
Array.of(1, 2, 3)→[1, 2, 3]Array.from('abc')→['a', 'b', 'c'](类数组转数组)Array.from([1, 2], x => x * 2)→[2, 4](带 map 功能)
✅ 特别适合从类数组对象(如 arguments、DOM NodeList)创建真正的数组。
❌ 二、怎么“删”掉数组里的元素?—— 删(Remove)
1. pop():弹出最后一个
删除并返回数组最后一个元素。
const arr = [1, 2, 3];
arr.pop(); // 返回 3,arr 变成 [1, 2]
✅ 常用于栈结构操作。
2. shift():去掉第一个
删除并返回第一个元素。
const arr = [1, 2, 3];
arr.shift(); // 返回 1,arr 变成 [2, 3]
⚠️ 同样会重排索引,性能开销大。
3. splice():精准删除
指定从哪个位置开始,删几个。
const arr = [1, 2, 3, 4];
arr.splice(1, 2); // 从索引1开始删2个 → [1, 4]
✅ 最灵活的删除方式,支持插入+删除组合。
4. slice(start, end):切片(其实是“查”但常被误认为“删”)
注意!slice 不会改变原数组,而是返回一个新数组片段。
const arr = [1, 2, 3, 4];
const sub = arr.slice(1, 3); // [2, 3]
// arr 还是 [1, 2, 3, 4]
✅ 常用于“复制”部分元素,比如实现分页、截取前N项等。
🛠️ 三、怎么“改”变数组内容?—— 改(Modify)
1. splice() 再次登场:替换元素
不仅可以删和增,还能实现“替换”。
const arr = [1, 2, 3];
arr.splice(1, 1, 'x'); // 删除1个,插入'x' → [1, 'x', 3]
✅ 实现局部更新的利器。
2. sort(compareFn):排序
对数组进行原地排序(会改变原数组)。
[3, 1, 2].sort(); // [1, 2, 3]
// 自定义排序:按长度排字符串
// 创建一个变量来存储数组
const myArray = ['a', 'ccc', 'bb'];
// 对变量调用sort方法
myArray.sort((a, b) => a.length - b.length);
// 输出排序后的数组
console.log(myArray);
//[ 'a', 'bb', 'ccc' ]
⚠️ 注意:默认按字符串Unicode排序,数字排序一定要传 compareFn!
3. reverse():反转数组
把数组顺序倒过来。
[1, 2, 3].reverse(); // [3, 2, 1]
✅ 原地反转,常用于倒序展示。
4. fill(value, start?, end?):填充统一值
把一段区间全部填成某个值。
new Array(5).fill(0); // [0, 0, 0, 0, 0]
[1, 2, 3, 4].fill('x', 1, 3); // [1, 'x', 'x', 4]
✅ 初始化数组或批量赋值很方便。
5. copyWithin(target, start, end?):内部复制
把数组内部某段内容复制到另一个位置。
[1, 2, 3, 4, 5].copyWithin(0, 3); // 把索引3开始的复制到0 → [4, 5, 3, 4, 5]
✅ 小众但有趣,适合特定算法场景。
🔍 四、怎么“查”找数组中的元素?—— 查(Search)
1. indexOf(item) 和 lastIndexOf(item)
查找元素的索引位置,前者从前往后,后者从后往前。
const arr = [1, 2, 3, 2];
arr.indexOf(2); // 1
arr.lastIndexOf(2); // 3
✅ 找不到返回 -1,适合简单查找。
2. includes(item):是否存在?
判断数组是否包含某个值,返回 true/false。
[1, 2, 3].includes(2); // true
✅ 比 indexOf !== -1 更语义化,推荐使用。
3. find(callback) 和 findIndex(callback)
按条件查找第一个匹配的元素或其索引。
const users = [{id: 1, name: 'Alice'}, {id: 2, name: 'Bob'}];
users.find(u => u.id === 2); // {id: 2, name: 'Bob'}
users.findIndex(u => u.name === 'Alice'); // 0
✅ 适合对象数组查找,非常实用!
4. findLast() 和 findLastIndex()(ES2023)
从末尾开始查找第一个匹配项。
[1, 2, 3, 2].findLastIndex(x => x === 2); // 3
✅ 新增方法,填补了“反向查找”的空白。
🔁 五、怎么“遍历”数组?—— 遍历(Iterate)
这部分是数组操作的核心,也是面试常考点!
1. forEach(callback):简单遍历
执行一个函数对每个元素,不返回新数组。
[1, 2, 3].forEach(console.log);
⚠️ 注意:不能中途 break 或 continue,除非用 try/catch 抛异常(不推荐):
try {
arr.forEach(item => {
if (item === 5) throw new Error('stop');
});
} catch {}
✅ 建议:如果不需要返回值,用 forEach 更语义清晰。
2. map(callback):映射成新数组
对每个元素执行函数,返回一个新数组。
[1, 2, 3].map(x => x * 2); // [2, 4, 6]
✅ 支持链式调用,如 .map().filter().sort(),是函数式编程的基石。
📌 map vs forEach:
| 对比项 | map | forEach |
|---|---|---|
| 返回值 | 新数组 | undefined |
| 是否改变原数组 | 否 | 否 |
| 链式调用 | ✅ 可以 | ❌ 不能 |
| 性能 | 稍慢(创建新数组) | 稍快(无返回) |
| 使用场景 | 需要转换数据结构 | 仅执行副作用(如打印) |
3. filter(callback):筛选符合条件的元素
返回一个新数组,只包含满足条件的元素。
[1, 2, 3, 4].filter(x => x > 2); // [3, 4]
✅ 常用于搜索、过滤列表。
4. reduce(callback, initialValue):累计器
将数组“压缩”成一个值,功能极其强大。
[1, 2, 3].reduce((acc, cur) => acc + cur, 0); // 6
✅ 可实现:求和、扁平化、统计、对象分组等高级操作。
5. some() 和 every():条件判断
some():是否有至少一个元素满足条件?every():是否所有元素都满足条件?
[1, 2, 3].some(x => x > 2); // true
[1, 2, 3].every(x => x > 0); // true
✅ 适合做“存在性”或“全量”校验,比如表单验证。
6. 其他实用方法
flat(depth):扁平化多维数组
[1, [2, 3], [4, [5]]].flat(2); // [1, 2, 3, 4, 5]
flatMap(callback):先 map 再 flat
['a b', 'c d'].flatMap(str => str.split(' ')); // ['a', 'b', 'c', 'd']
✅ 适合处理“一对多”映射后的扁平化。
🎯 总结:一张表帮你理清思路
| 类别 | 方法 | 是否改变原数组 | 是否返回新数组 | 典型用途 |
|---|---|---|---|---|
| 增 | push, unshift, splice | ✅ 是 | ❌ 否 | 添加元素 |
concat, Array.from/of | ❌ 否 | ✅ 是 | 创建新数组 | |
| 删 | pop, shift, splice | ✅ 是 | ❌ 否 | 删除元素 |
slice | ❌ 否 | ✅ 是 | 截取片段 | |
| 改 | sort, reverse, fill, copyWithin, splice | ✅ 是 | ❌ 否 | 修改内容 |
| 查 | indexOf, includes, find, findIndex 等 | ❌ 否 | ❌ 否(返回索引/元素) | 查找 |
| 遍历 | forEach | ❌ 否 | ❌ 否 | 执行副作用 |
map, filter, flatMap | ❌ 否 | ✅ 是 | 转换/筛选 | |
reduce | ❌ 否 | ✅ 是(单值) | 累计计算 | |
some, every | ❌ 否 | ✅ 是(布尔) | 条件判断 |
💡 最后的小建议
- 能用
for...of或普通for循环时,性能最好,尤其是大数据量。 - 函数式方法(map/filter/reduce)更优雅、可读性强,适合处理逻辑转换。
- 避免滥用
splice修改大数组,性能较差。 - 优先使用
const+ 不变操作(如map、filter),减少副作用。
新方法的兼容性提醒
-
findLast()/findLastIndex()(ES2023) -
flat()/flatMap()(ES2019)这些方法在老旧浏览器(特别是 IE 和早期的移动端 WebView)是不支持的。 需注意兼容性,可用 polyfill 或 Babel 转译。
希望这篇文章能帮你系统梳理JS数组的常用方法,下次写代码时,再也不用翻文档啦!