JavaScript 数组方法完全指南

小飞兽 JavaScript 400 次阅读 2026-06-18

JavaScript 数组方法完全指南

Introduction

JavaScript 数组是现代前端开发中最核心的数据结构之一,而数组方法则是每位开发者必须掌握的利器。从 mapfilterreduce 三大函数式方法,到 findsomeevery 等查询方法,再到 pushpopsplice 等变更方法,JavaScript 为我们提供了丰富而强大的数组操作API。掌握这些方法,不仅能让代码更简洁优雅,还能显著提升开发效率。本文将系统梳理ES6以来最常用的数组方法,通过基础语法讲解、代码示例演示、运行效果展示、常见问题解析以及延伸阅读推荐,帮助你建立完整的数组方法知识体系。

一、遍历类方法(Iteration Methods)

1. forEach — 逐项遍历

forEach 是最基础的遍历方法,它对数组中的每个元素执行一次提供的函数,没有返回值。

基础语法:

array.forEach(callback(currentValue[, index[, array]])[, thisArg])

代码示例:

const fruits = ['苹果', '香蕉', '橙子'];

fruits.forEach((item, index, arr) => {
    console.log(`索引 ${index}: ${item}`);
});
// 输出:
// 索引 0: 苹果
// 索引 1: 香蕉
// 索引 2: 橙子

运行效果:

索引 0: 苹果
索引 1: 香蕉
索引 2: 橙子

注意事项: forEach 无法使用 breakreturn 跳出循环。如果需要中断遍历,应使用 for...of 循环或 some/every 方法。

---

2. map — 映射转换

map 创建一个新数组,其结果是该数组中的每个元素都调用提供的函数后的返回值。

基础语法:

const newArray = array.map(callback(currentValue[, index[, array]])[, thisArg])

代码示例:

const numbers = [1, 2, 3, 4, 5];

// 求平方
const squared = numbers.map(n => n * n);
console.log('平方数组:', squared);

// 对象属性提取
const users = [
    { name: '张三', age: 25 },
    { name: '李四', age: 30 },
    { name: '王五', age: 28 }
];
const names = users.map(user => user.name);
console.log('用户名列表:', names);

运行效果:

平方数组: [1, 4, 9, 16, 25]
用户名列表: ['张三', '李四', '王五']

注意事项: map 不会改变原数组(除非回调函数内部做了修改),且始终返回一个新数组。如果不需要返回值,应使用 forEach

---

3. filter — 条件过滤

filter 创建一个包含所有通过测试函数测试的元素的新数组。

基础语法:

const newArray = array.filter(callback(element[, index[, array]])[, thisArg])

代码示例:

const scores = [85, 42, 93, 67, 78, 55, 91];

// 过滤及格分数
const passed = scores.filter(score => score >= 60);
console.log('及格成绩:', passed);

// 过滤偶数
const evens = [1, 2, 3, 4, 5, 6].filter(n => n % 2 === 0);
console.log('偶数:', evens);

// 过滤对象数组
const products = [
    { name: '手机', price: 2999, inStock: true },
    { name: '电脑', price: 5999, inStock: false },
    { name: '耳机', price: 199, inStock: true }
];
const availableProducts = products.filter(p => p.inStock);
console.log('有货商品:', availableProducts.map(p => p.name));

运行效果:

及格成绩: [85, 93, 67, 78, 91]
偶数: [2, 4, 6]
有货商品: ['手机', '耳机']

---

4. reduce — 聚合归纳

reduce 对数组中的每个元素按序执行一个提供的 reducer 函数,将其结果汇总为单个值。

基础语法:

array.reduce(callback(accumulator, currentValue[, index[, array]])[, initialValue])

代码示例:

const numbers = [1, 2, 3, 4, 5];

// 求和
const sum = numbers.reduce((acc, cur) => acc + cur, 0);
console.log('总和:', sum);

// 求积
const product = numbers.reduce((acc, cur) => acc * cur, 1);
console.log('乘积:', product);

// 转换为对象
const fruitCounts = ['苹果', '香蕉', '苹果', '橙子', '香蕉', '苹果'];
const countMap = fruitCounts.reduce((acc, fruit) => {
    acc[fruit] = (acc[fruit] || 0) + 1;
    return acc;
}, {});
console.log('水果计数:', countMap);

运行效果:

总和: 15
乘积: 120
水果计数: { '苹果': 3, '香蕉': 2, '橙子': 1 }

---

二、查询类方法(Searching Methods)

5. find / findIndex / findLast

基础语法:

array.find(callback(element[, index[, array]])[, thisArg])
array.findIndex(callback(element[, index[, array]])[, thisArg])
array.findLast(callback(element[, index[, array]])[, thisArg]) // ES2023

代码示例:

const users = [
    { id: 1, name: '张三', role: 'admin' },
    { id: 2, name: '李四', role: 'user' },
    { id: 3, name: '王五', role: 'admin' }
];

// find — 找到第一个匹配元素
const admin = users.find(u => u.role === 'admin');
console.log('第一个管理员:', admin.name);

// findIndex — 找到第一个匹配元素的索引
const adminIndex = users.findIndex(u => u.role === 'admin');
console.log('第一个管理员索引:', adminIndex);

// findLast — 找到最后一个匹配元素(ES2023)
const lastAdmin = users.findLast(u => u.role === 'admin');
console.log('最后一个管理员:', lastAdmin.name);

运行效果:

第一个管理员: 张三
第一个管理员索引: 0
最后一个管理员: 王五

---

6. some / every — 布尔查询

基础语法:

array.some(callback(element[, index[, array]])[, thisArg])
array.every(callback(element[, index[, array]])[, thisArg])

代码示例:

const ages = [18, 22, 15, 30, 25];

// some — 是否有任何元素满足条件
const hasMinor = ages.some(age => age < 18);
console.log('是否有未成年人:', hasMinor);

// every — 是否所有元素都满足条件
const allAdult = ages.every(age => age >= 18);
console.log('是否全部成年:', allAdult);

运行效果:

是否有未成年人: false
是否全部成年: true

---

7. includes / indexOf / lastIndexOf

基础语法:

array.includes(searchElement[, fromIndex])
array.indexOf(searchElement[, fromIndex])
array.lastIndexOf(searchElement[, fromIndex])

代码示例:

const nums = [1, 2, 3, 4, 2, 5, 2];

console.log('包含3:', nums.includes(3));        // true
console.log('首次出现2:', nums.indexOf(2));     // 1
console.log('最后出现2:', nums.lastIndexOf(2)); // 6

运行效果:

包含3: true
首次出现2: 1
最后出现2: 6

---

三、变更类方法(Mutating Methods)

8. push / pop — 末尾操作

基础语法:

array.push(element1[, ...[, elementN]])   // 返回新长度
array.pop()                                // 返回被移除元素

代码示例:

const stack = [1, 2, 3];

stack.push(4);
console.log('push后:', stack);

const removed = stack.pop();
console.log('pop移除:', removed);
console.log('pop后:', stack);

运行效果:

push后: [1, 2, 3, 4]
pop移除: 4
pop后: [1, 2, 3]

---

9. unshift / shift — 头部操作

基础语法:

array.unshift(element1[, ...[, elementN]])  // 返回新长度
array.shift()                                  // 返回被移除元素

代码示例:

const queue = ['A', 'B', 'C'];

queue.unshift('START');
console.log('unshift后:', queue);

const first = queue.shift();
console.log('shift移除:', first);
console.log('shift后:', queue);

运行效果:

unshift后: ['START', 'A', 'B', 'C']
shift移除: START
shift后: ['A', 'B', 'C']

---

10. splice — 任意位置增删改

splice 是最强大的变更方法,可以从数组中添加或删除元素。

基础语法:

array.splice(start[, deleteCount[, item1[, item2[, ...]]]])

代码示例:

const colors = ['红', '绿', '蓝', '黄', '紫'];

// 删除:移除索引1开始的2个元素
const deleted = colors.splice(1, 2);
console.log('删除的元素:', deleted);
console.log('删除后:', colors);

// 插入:在索引1处插入新元素
colors.splice(1, 0, '粉', '橙');
console.log('插入后:', colors);

// 替换:替换索引2的元素
colors.splice(2, 1, '黑');
console.log('替换后:', colors);

运行效果:

删除的元素: ['绿', '蓝']
删除后: ['红', '黄', '紫']
插入后: ['红', '粉', '橙', '黄', '紫']
替换后: ['红', '粉', '黑', '黄', '紫']

---

四、排序与反转

11. sort — 排序

基础语法:

array.sort([compareFunction(compareFirst, compareSecond)])

代码示例:

const nums = [3, 1, 4, 1, 5, 9, 2, 6];

// 默认字典序(注意:默认会转字符串比较!)
const defaultSort = [...nums].sort();
console.log('默认排序:', defaultSort);

// 数值排序
const numericSort = [...nums].sort((a, b) => a - b);
console.log('升序:', numericSort);

const descendingSort = [...nums].sort((a, b) => b - a);
console.log('降序:', descendingSort);

// 字符串排序
const names = ['Tom', 'Alice', 'Bob', 'Diana'];
console.log('字母排序:', [...names].sort());

运行效果:

默认排序: [1, 2, 3, 4, 5, 6, 9]
升序: [1, 1, 2, 3, 4, 5, 6, 9]
降序: [9, 6, 5, 4, 3, 2, 1, 1]
字母排序: ['Alice', 'Bob', 'Diana', 'Tom']

常见问题: sort() 默认按字符串Unicode码点排序,所以 [1, 2, 10].sort() 会得到 [1, 10, 2]。务必传入比较函数处理数字排序。

---

12. reverse — 反转

基础语法:

array.reverse()

代码示例:

const arr = [1, 2, 3, 4, 5];
const reversed = [...arr].reverse();
console.log('反转后:', reversed);

运行效果:

反转后: [5, 4, 3, 2, 1]

---

五、组合与切片

13. concat — 合并

基础语法:

const newArray = array1.concat(array2[, ...[, arrayN]])

代码示例:

const a = [1, 2];
const b = [3, 4];
const c = [5, 6];
console.log('合并:', a.concat(b, c));

运行效果:

合并: [1, 2, 3, 4, 5, 6]

---

14. slice — 切片

基础语法:

array.slice([begin[, end]])

代码示例:

const letters = ['A', 'B', 'C', 'D', 'E'];

// 提取前3个
console.log('前3个:', letters.slice(0, 3));

// 提取最后2个
console.log('最后2个:', letters.slice(-2));

// 复制整个数组(浅拷贝)
const copy = letters.slice();
console.log('拷贝:', copy);

运行效果:

前3个: ['A', 'B', 'C']
最后2个: ['D', 'E']
拷贝: ['A', 'B', 'C', 'D', 'E']

---

15. flat / flatMap — 扁平化

基础语法:

array.flat([depth])       // depth默认为1
array.flatMap(callback(currentValue[, index[, array]])[, thisArg])

代码示例:

// flat — 扁平化数组
const nested = [1, [2, [3, [4]]]];
console.log('扁平1层:', nested.flat(1));
console.log('完全扁平:', nested.flat(Infinity));

// flatMap — 先map后flat(常用于数据转换)
const sentences = ['Hello world', 'How are you'];
const words = sentences.flatMap(s => s.split(' '));
console.log('单词列表:', words);

运行效果:

扁平1层: [1, 2, [3, [4]]]
完全扁平: [1, 2, 3, 4]
单词列表: ['Hello', 'world', 'How', 'are', 'you']

---

六、其他实用方法

16. join — 拼接为字符串

基础语法:

array.join([separator])

代码示例:

const parts = ['首页', '文章', '列表'];
console.log('默认连接:', parts.join());
console.log('斜杠连接:', parts.join('/'));
console.log('箭头连接:', parts.join(' → '));

运行效果:

默认连接: 首页,文章,列表
斜杠连接: 首页/文章/列表
箭头连接: 首页 → 文章 → 列表

---

17. at — 索引访问(ES2022)

基础语法:

array.at(index)  // 支持负索引

代码示例:

const arr = [10, 20, 30, 40, 50];
console.log('第一个:', arr.at(0));
console.log('最后一个:', arr.at(-1));
console.log('倒数第2个:', arr.at(-2));

运行效果:

第一个: 10
最后一个: 50
倒数第2个: 40

---

七、常见问题(FAQ)

Q1:map、filter 和 forEach 的区别是什么?
forEach 无返回值,纯粹用于遍历副作用;map 返回新数组(每个元素被转换);filter 返回新数组(只保留满足条件的元素)。

Q2:如何正确对数字数组排序?

// ❌ 错误
[1, 10, 2].sort(); // [1, 10, 2]
// ✅ 正确
[1, 10, 2].sort((a, b) => a - b); // [1, 2, 10]

Q3:reduce 的 initialValue 什么时候必须提供?
当数组可能为空时,建议始终提供 initialValue,否则空数组会抛出 TypeError

Q4:splice 和 slice 的区别?
splice 修改原数组(删除/替换/插入),而 slice 返回新数组(原数组不变)。

Q5:如何深拷贝一个数组?

const deep = JSON.parse(JSON.stringify(arr));      // 简单但有限制
const deep2 = arr.map(item => ({ ...item }));      // 浅拷贝对象元素
const deep3 = structuredClone(arr);                  // ES2023原生深拷贝

Q6:find 和 filter 的区别?
find 返回第一个匹配的元素(或 undefined),filter 返回所有匹配元素组成的新数组。

---

八、延伸阅读

1. MDN Web Docs — Arrayhttps://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Array 官方文档,包含完整的方法列表和详细说明。
2. JavaScript Array 进阶:完全攻略:深入讲解函数式编程思想在数组操作中的应用。
3. ES2022 新特性 — Array.at():MDN关于ES2022新增索引方法的介绍。
4. 你不知道的 JavaScript:经典系列书籍,帮助深入理解 JavaScript 底层机制。
5. Lodash 数组方法对比:学习 Lodash 如何对原生数组方法进行补充和增强。