JavaScript数组方法
112 JavaScript数组方法(forEach, map, filter, reduce等)笔记
一、核心主题
本章节聚焦JavaScript中处理数组的现代高阶函数方法,重点讲解forEach、map、filter、reduce四大核心数组方法的语法、参数、返回值及典型应用场景,通过对比传统循环方式,掌握函数式编程思想在数组处理中的应用,提升代码简洁性和可维护性。
二、forEach方法:遍历数组
2.1 基本语法与特点
- 作用:对数组的每个元素执行一次提供的回调函数
- 返回值:undefined(无返回值)
- 是否修改原数组:不会直接修改,但可在回调中修改
1 2 3
| array.forEach(function (currentValue, index, array) { }, thisArg);
|
参数说明:
currentValue:当前元素值
index:当前元素索引(可选)
array:原数组本身(可选)
thisArg:执行回调函数时用作this的值(可选)
2.2 例题:打印餐厅菜单
1 2 3 4 5 6 7 8 9 10 11
| const menu = ["凯撒沙拉", "菲力牛排", "松露意面"];
menu.forEach(function (dish) { console.log("菜品:", dish); });
|
2.3 例题:带索引的菜单打印
1 2 3 4 5 6 7 8 9 10
| const menu = ["凯撒沙拉", "菲力牛排", "松露意面"];
menu.forEach(function (dish, index) { console.log(`${index + 1}. ${dish}`); });
|
2.4 forEach vs for-of循环
| 特性 |
forEach |
for-of |
| 返回值 |
undefined |
无 |
| break/continue |
不支持 |
支持 |
| 回调函数 |
需要 |
不需要 |
| 代码简洁度 |
高 |
高 |
重要提示:forEach无法使用break或continue中断循环,必须遍历所有元素。
三、map方法:转换数组
3.1 基本语法与特点
- 作用:对数组的每个元素执行回调函数,返回由处理结果组成的新数组
- 返回值:新数组(与原数组长度相同)
- 是否修改原数组:不修改,返回新数组
1 2 3
| const newArray = array.map(function (currentValue, index, array) { }, thisArg);
|
3.2 例题:计算菜品价格翻倍
1 2 3 4 5 6 7 8 9
| const prices = [15, 28, 32, 18];
const doubledPrices = prices.map(function (price) { return price * 2; });
console.log(doubledPrices); console.log(prices);
|
3.3 例题:将菜单名称转为大写
1 2 3 4 5 6 7
| const menu = ["caesar salad", "beef steak", "truffle pasta"];
const upperMenu = menu.map(function (dish) { return dish.toUpperCase(); });
console.log(upperMenu);
|
3.4 map的陷阱:必须return
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| const numbers = [1, 2, 3];
const result = numbers.map(function (num) { num * 2; });
console.log(result);
const correct = numbers.map(function (num) { return num * 2; }); console.log(correct);
|
四、filter方法:过滤数组
4.1 基本语法与特点
- 作用:根据指定条件过滤数组元素,返回满足条件的新数组
- 返回值:新数组(包含满足条件的元素)
- 是否修改原数组:不修改
1 2 3
| const newArray = array.filter(function (currentValue, index, array) { }, thisArg);
|
4.2 例题:筛选素食菜品
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| const menu = [ { name: "凯撒沙拉", vegetarian: true }, { name: "菲力牛排", vegetarian: false }, { name: "蔬菜汤", vegetarian: true }, { name: "三文鱼", vegetarian: false }, ];
const vegetarianDishes = menu.filter(function (dish) { return dish.vegetarian === true; });
console.log(vegetarianDishes);
|
4.3 例题:筛选价格大于20的菜品
1 2 3 4 5 6 7 8 9 10 11 12 13
| const dishes = [ { name: "沙拉", price: 15 }, { name: "牛排", price: 28 }, { name: "意面", price: 18 }, { name: "龙虾", price: 45 }, ];
const expensiveDishes = dishes.filter(function (dish) { return dish.price > 20; });
console.log(expensiveDishes);
|
4.4 filter的回调必须返回布尔值
1 2 3 4 5 6 7 8
| const numbers = [1, 2, 3, 4, 5];
const evens = numbers.filter(function (num) { return num % 2 === 0; });
console.log(evens);
|
五、reduce方法:累积数组
5.1 基本语法与特点
- 作用:对数组的每个元素执行回调函数,将其结果累积为单个返回值
- 返回值:累积后的单个值(可以是任意类型)
- 是否修改原数组:不修改
1 2 3 4 5 6 7 8
| const result = array.reduce(function ( accumulator, currentValue, currentIndex, array, ) { }, initialValue);
|
参数说明:
accumulator:累积器,存储回调的返回值
currentValue:当前元素值
currentIndex:当前索引(可选)
array:原数组(可选)
initialValue:初始值(可选,重要!)
5.2 例题:计算菜单总价
1 2 3 4 5 6 7 8 9 10 11 12 13
| const prices = [15, 28, 32, 18];
const total = prices.reduce(function (acc, price) { return acc + price; }, 0);
console.log(total);
|
5.3 例题:找出最贵菜品
1 2 3 4 5 6 7 8 9 10 11 12
| const dishes = [ { name: "沙拉", price: 15 }, { name: "牛排", price: 28 }, { name: "意面", price: 18 }, { name: "龙虾", price: 45 }, ];
const mostExpensive = dishes.reduce(function (acc, dish) { return dish.price > acc.price ? dish : acc; });
console.log(mostExpensive);
|
5.4 陷阱:忘记初始值
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| const numbers = [1, 2, 3, 4];
const sum1 = numbers.reduce(function (acc, num) { return acc + num; }); console.log(sum1);
const sum2 = numbers.reduce(function (acc, num) { return acc + num; }, 0); console.log(sum2);
const empty = [];
const safe = empty.reduce((acc, num) => acc + num, 0);
|
六、方法链式调用
6.1 链式调用原理
数组方法返回数组(map/filter),可继续调用其他数组方法,形成链式调用,代码更简洁。
6.2 例题:筛选、转换、求和
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| const transactions = [ { type: "deposit", amount: 100 }, { type: "withdrawal", amount: 50 }, { type: "deposit", amount: 200 }, { type: "withdrawal", amount: 30 }, ];
const totalDeposits = transactions .filter(function (t) { return t.type === "deposit"; }) .map(function (t) { return t.amount; }) .reduce(function (acc, amount) { return acc + amount; }, 0);
console.log(totalDeposits);
const totalDepositsArrow = transactions .filter((t) => t.type === "deposit") .map((t) => t.amount) .reduce((acc, amount) => acc + amount, 0);
|
6.3 链式调用顺序的重要性
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| const numbers = [1, 2, 3, 4, 5];
const result1 = numbers .filter((num) => num % 2 === 0) .map((num) => num * 2);
const result2 = numbers .map((num) => num * 2) .filter((num) => num % 4 === 0);
console.log(result1, result2);
|
七、find和findIndex方法
7.1 find方法
- 作用:返回数组中满足条件的第一个元素
- 返回值:找到的元素或undefined
1 2 3 4 5 6 7 8 9 10 11 12
| const dishes = [ { name: "沙拉", price: 15 }, { name: "牛排", price: 28 }, { name: "意面", price: 18 }, ];
const expensiveDish = dishes.find(function (dish) { return dish.price > 20; });
console.log(expensiveDish);
|
7.2 findIndex方法
- 作用:返回数组中满足条件的第一个元素的索引
- 返回值:索引或-1
1 2 3 4 5 6 7
| const menu = ["沙拉", "牛排", "意面"];
const index = menu.findIndex(function (dish) { return dish === "牛排"; });
console.log(index);
|
八、some和every方法
8.1 some方法
- 作用:检查数组中是否至少有一个元素满足条件
- 返回值:布尔值
1 2 3 4 5 6 7 8 9 10 11 12
| const dishes = [ { name: "沙拉", vegetarian: true }, { name: "牛排", vegetarian: false }, { name: "意面", vegetarian: false }, ];
const hasVegetarian = dishes.some(function (dish) { return dish.vegetarian === true; });
console.log(hasVegetarian);
|
8.2 every方法
- 作用:检查数组中是否所有元素都满足条件
- 返回值:布尔值
1 2 3 4 5 6 7 8 9 10 11 12
| const dishes = [ { name: "沙拉", vegetarian: true }, { name: "蔬菜汤", vegetarian: true }, { name: "水果拼盘", vegetarian: true }, ];
const allVegetarian = dishes.every(function (dish) { return dish.vegetarian === true; });
console.log(allVegetarian);
|
九、数组方法对比总结
9.1 核心方法对比表
| 方法 |
作用 |
返回值 |
是否修改原数组 |
是否支持链式 |
| forEach |
遍历 |
undefined |
否 |
否 |
| map |
转换 |
新数组 |
否 |
是 |
| filter |
过滤 |
新数组 |
否 |
是 |
| reduce |
累积 |
单个值 |
否 |
否 |
| find |
查找第一个 |
元素/undefined |
否 |
否 |
| findIndex |
查找索引 |
索引/-1 |
否 |
否 |
| some |
判断存在 |
布尔值 |
否 |
否 |
| every |
判断全部 |
布尔值 |
否 |
否 |
9.2 使用场景决策树
- 仅需遍历,不返回结果 → forEach
- 需要转换数组元素 → map
- 需要筛选满足条件元素 → filter
- 需要汇总为单个值 → reduce
- 查找第一个匹配元素 → find/findIndex
- 判断数组是否满足条件 → some/every
- 需要中断循环 → for-of
9.3 箭头函数简写
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| const doubled = numbers.map(function (num) { return num * 2; });
const doubledArrow = numbers.map((num) => num * 2);
const indexed = menu.map((dish, index) => `${index}: ${dish}`);
const processed = items.map((item) => { const tax = item.price * 0.1; return { ...item, priceWithTax: item.price + tax, }; });
|
十、总结:数组方法的核心要点
- 不可变性:map、filter、reduce等方法不修改原数组,返回新数据
- 函数式编程:将循环逻辑抽象为函数,代码更声明式
- 链式调用:map和filter返回数组,可继续调用其他方法
- 回调函数:所有方法都接收回调函数,参数位置固定
- 箭头函数:配合箭头函数可大幅简化代码
- 性能考虑:大规模数据时,链式调用可能多次遍历数组
- 选择合适方法:根据需求选择最匹配的方法,避免滥用forEach