JavaScript数组核心方法全面讲解(附多场景示例)

 更新时间:2026年03月26日 10:47:34   作者:TON_G-T  
JavaScript数组是Web开发中处理数据的核心工具,提供了多种内置方法以高效操作数组元素,下面这篇文章主要介绍了JavaScript数组核心方法的相关资料,文中通过代码介绍的非常详细,需要的朋友可以参考下

一、核心概念

JavaScript 数组的内置方法是开发中最常用的工具,也是面试高频考点,核心:

  • 功能:方法的核心作用
  • 返回值:执行后返回什么(新数组 / 单个值 /undefined)
  • 可变性:是否修改原数组(mutability)
  • 使用场景:与其他方法的对比和选型
分类包含方法核心特征
迭代遍历方法forEach、map、filter、reduce、some、every遍历数组元素并执行逻辑
修改原数组(Mutator)push、pop、shift、unshift、splice、sort、reverse直接改变原数组,有副作用
返回新数组(Non-mutating)map、filter、concat、slice原数组不变,返回新数组
查找判断方法find、findIndex、includes、indexOf查找元素或判断存在性

二、为什么要深入理解?

  1. 代码简洁高效:用高阶方法替代冗余的 for 循环,提升代码可读性和维护性;
  2. 避免副作用:明确可变性,防止在 React/Vue/Redux 等状态管理中误改原数据;
  3. 面试核心考点:手动实现 map/reduce、区分 slice/splice、判断方法可变性是高频面试题;
  4. 性能优化:不同方法的执行效率不同(如 reduce 比嵌套循环更高效)。

三、核心方法详解(附多场景示例)

1. 迭代遍历方法

(1) map () - 数组转换(返回新数组)工作中最常使用

  • 核心:遍历数组,对每个元素执行回调,返回新数组(长度与原数组一致)
  • 可变性:不修改原数组
  • 返回值:新数组
  • 适用场景:数据格式转换、批量处理元素

基础示例

const numbers = [1, 4, 9];
const doubles = numbers.map(num => num * 2);
console.log(doubles); // [2, 8, 18]
console.log(numbers); // [1, 4, 9](原数组不变)

实战示例:对象数组属性提取

const users = [
  { id: 1, name: '张三', age: 20 },
  { id: 2, name: '李四', age: 25 },
  { id: 3, name: '王五', age: 30 }
];
// 提取所有用户名
const userNames = users.map(user => user.name);
console.log(userNames); // ["张三", "李四", "王五"]
// 批量修改属性(返回新对象)
const adultUsers = users.map(user => ({
  ...user,
  isAdult: user.age >= 18 // 新增属性
}));
console.log(adultUsers[0]); // { id: 1, name: '张三', age: 20, isAdult: true }

(2) filter () - 数组过滤(返回新数组)

  • 核心:遍历数组,筛选出符合条件的元素,返回新数组
  • 可变性:不修改原数组
  • 返回值:新数组(长度≤原数组)
  • 适用场景:数据筛选、条件过滤

基础示例

const words = ['spray', 'limit', 'elite', 'exuberant', 'destruction'];
const longWords = words.filter(word => word.length > 6);
console.log(longWords); // ["exuberant", "destruction"]
[].filter(Boolean) //可以过滤掉null

实战示例:多条件过滤

const products = [
  { name: '手机', price: 2999, category: '数码', stock: 50 },
  { name: '耳机', price: 199, category: '数码', stock: 0 },
  { name: 'T恤', price: 99, category: '服饰', stock: 100 },
  { name: '键盘', price: 499, category: '数码', stock: 30 }
];
// 筛选:数码类、价格<500、有库存的商品
const validProducts = products.filter(p => 
  p.category === '数码' && p.price < 500 && p.stock > 0
);
console.log(validProducts); // [{ name: '耳机', ... }, { name: '键盘', ... }]

(3) reduce () - 数组归并(返回单个值)

  • 核心:遍历数组,将元素 “累积” 为单个值(数字、对象、数组等)
  • APIarr.reduce((acc, cur, idx, arr) => {}, initialValue)
    • acc:累加器(上一次回调的返回值 / 初始值)
    • cur:当前元素
    • initialValue:可选,累加器初始值(推荐必传)
  • 可变性:不修改原数组
  • 适用场景:求和 / 求积、数组转对象、扁平数组、分组统计

基础示例:求和

const array = [1, 2, 3, 4];
const sum = array.reduce((acc, cur) => acc + cur, 0);
console.log(sum); // 10

实战示例 1:数组转对象(按 ID 映射)

const users = [
  { id: 1, name: '张三' },
  { id: 2, name: '李四' },
  { id: 3, name: '王五' }
];
// 转换为 { 1: { id:1, name:'张三' }, 2: { ... } }
const userMap = users.reduce((acc, cur) => {
  acc[cur.id] = cur;
  return acc;
}, {});
console.log(userMap[2]); // { id: 2, name: '李四' }

实战示例 2:扁平嵌套数组

const nestedArr = [1, [2, [3, 4], 5], 6];
const flatArr = nestedArr.reduce((acc, cur) => {
  return acc.concat(Array.isArray(cur) ? cur.reduce((a, c) => a.concat(c), []) : cur);
}, []);
console.log(flatArr); // [1, 2, 3, 4, 5, 6]

实战示例 3:分组统计

const scores = [
  { name: '张三', subject: '数学', score: 90 },
  { name: '张三', subject: '语文', score: 85 },
  { name: '李四', subject: '数学', score: 88 },
  { name: '李四', subject: '语文', score: 92 }
];
// 按姓名分组,统计总分
const scoreSum = scores.reduce((acc, cur) => {
  if (!acc[cur.name]) {
    acc[cur.name] = 0;
  }
  acc[cur.name] += cur.score;
  return acc;
}, {});
console.log(scoreSum); // { 张三: 175, 李四: 180 }

(4) forEach () - 遍历执行(无返回值)

  • 核心:遍历数组,对每个元素执行回调(仅执行操作,无返回值)
  • 可变性:本身不修改原数组,但回调中可手动修改
  • 返回值:undefined
  • 适用场景:执行副作用操作(如打印、调用 API、修改 DOM)

示例

const fruits = ['苹果', '香蕉', '橙子'];
// 打印每个元素
fruits.forEach((fruit, index) => {
  console.log(`第${index+1}个水果:${fruit}`);
});
// 第1个水果:苹果 | 第2个水果:香蕉 | 第3个水果:橙子
// 注意:forEach 无法中断遍历(break 无效),需用 some/every 替代

(5) some ()/every () - 条件判断

  • some:只要有一个元素满足条件,返回 true(短路遍历)
  • every:所有元素满足条件,返回 true(短路遍历)
  • 返回值:布尔值
  • 适用场景:判断数组是否符合某个条件

示例

const numbers = [10, 20, 30, 35];
// some:是否有元素>30
const hasBigNum = numbers.some(num => num > 30);
console.log(hasBigNum); // true
// every:是否所有元素>15
const allBigNum = numbers.every(num => num > 15);
console.log(allBigNum); // false(10不满足)
// 实战:判断是否有已过期的订单
const orders = [
  { id: 1, expired: false },
  { id: 2, expired: true },
  { id: 3, expired: false }
];
const hasExpired = orders.some(order => order.expired);
console.log(hasExpired); // true

2. 修改原数组的方法(Mutator)

(1) splice () - 增删改数组(核心)

  • 核心:删除 / 插入 / 替换数组元素(原地修改)
  • APIarr.splice(start, deleteCount, item1, item2...)
    • start:起始索引(负数表示从末尾开始)
    • deleteCount:删除的元素数量(0 则不删除)
    • item...:要插入的元素
  • 返回值:被删除的元素组成的数组
  • 可变性:修改原数组

示例 1:插入元素

const months = ['Jan', 'March', 'April', 'June'];
// 索引1的位置,删除0个,插入'Feb'
const removed = months.splice(1, 0, 'Feb');
console.log(months); // ["Jan", "Feb", "March", "April", "June"]
console.log(removed); // [](无删除)

示例 2:删除元素

const arr = [1, 2, 3, 4, 5];
// 索引2的位置,删除2个元素
const deleted = arr.splice(2, 2);
console.log(arr); // [1, 2, 5]
console.log(deleted); // [3, 4]

示例 3:替换元素

const arr = ['a', 'b', 'c', 'd'];
// 索引1的位置,删除1个,插入'x'和'y'
arr.splice(1, 1, 'x', 'y');
console.log(arr); // ["a", "x", "y", "c", "d"]

(2) push/pop/shift/unshift - 数组首尾操作

方法功能返回值示例
push尾部添加元素新数组长度const arr = [1,2]; arr.push(3); // arr=[1,2,3],返回3
pop尾部删除元素被删除的元素const arr = [1,2,3]; arr.pop(); // arr=[1,2],返回3
unshift头部添加元素新数组长度const arr = [2,3]; arr.unshift(1); // arr=[1,2,3],返回3
shift头部删除元素被删除的元素const arr = [1,2,3]; arr.shift(); // arr=[2,3],返回1

(3) sort/reverse - 排序 / 反转

  • sort:原地排序,默认按字符串 Unicode 码排序(需传回调自定义规则)
  • reverse:原地反转数组顺序

示例

// sort 自定义排序(数字升序)
const numbers = [10, 2, 25, 5];
numbers.sort((a, b) => a - b);
console.log(numbers); // [2, 5, 10, 25]
// reverse 反转
const arr = [1, 2, 3];
arr.reverse();
console.log(arr); // [3, 2, 1]

3. 返回新数组的方法(Non-mutating)

(1) slice () - 截取数组片段

  • 核心:截取数组的指定范围,返回新数组(浅拷贝)
  • APIarr.slice(start, end)(start 包含,end 不包含,负数表示末尾)
  • 可变性:不修改原数组
  • 返回值:新数组

示例

const arr = [1, 2, 3, 4, 5];
// 截取索引1到3(不包含3)
const slice1 = arr.slice(1, 3);
console.log(slice1); // [2, 3]
// 截取最后2个元素
const slice2 = arr.slice(-2);
console.log(slice2); // [4, 5]
// 浅拷贝整个数组
const copyArr = arr.slice();
copyArr[0] = 10;
console.log(arr); // [1, 2, 3, 4, 5](原数组不变)

(2) concat () - 数组合并

  • 核心:合并多个数组 / 值,返回新数组
  • 可变性:不修改原数组
  • 返回值:新数组

示例

const arr1 = [1, 2];
const arr2 = [3, 4];
const arr3 = arr1.concat(arr2, 5);
console.log(arr3); // [1, 2, 3, 4, 5]
console.log(arr1); // [1, 2](原数组不变)

4. 易混淆方法对比

(1) map vs forEach

维度mapforEach
返回值新数组undefined
用途数据转换,需返回新数组执行操作(打印、调 API),无需返回值
链式调用支持(map ().filter ())不支持(返回 undefined)

(2) slice vs splice

维度slicesplice
可变性不修改原数组修改原数组
功能截取数组片段增删改数组元素
参数slice(start, end)splice(start, deleteCount, ...items)
返回值截取的新数组被删除的元素数组

(3) reduce 有无 initialValue 的区别

场景有 initialValue无 initialValue
空数组返回 initialValue抛出 TypeError
非空数组acc 初始值 = initialValue,从第一个元素开始遍历acc 初始值 = 第一个元素,从第二个元素开始遍历

示例

// 有 initialValue(推荐)
[1,2,3].reduce((acc, cur) => acc + cur, 0); // 6(acc初始=0,遍历1→2→3)
// 无 initialValue
[1,2,3].reduce((acc, cur) => acc + cur); // 6(acc初始=1,遍历2→3)
// 空数组 + 无 initialValue → 报错
// [].reduce((acc, cur) => acc + cur); // Uncaught TypeError

四、关键注意事项

  1. 可变性避坑
    • React/Vue 中,禁止直接修改 state 数组(如 state.arr.push(1)),需用非变异方法([...state.arr, 1]);
    • 如需修改原数组,先浅拷贝(const copy = [...arr])再操作。
  2. 稀疏数组处理
    • map/forEach/filter 会跳过稀疏数组的空位([1,,3].map(x => x*2)[2,,6]);
    • reduce 也会跳过空位(除非传 initialValue)。
  3. 性能优化
    • 避免嵌套迭代(如 map 里套 filter),优先用 reduce 一次遍历;
    • 大数据量遍历,for 循环比 forEach/map 更快(高阶方法有函数调用开销)。

手动实现核心方法(面试必考)

// 手动实现 map
Array.prototype.myMap = function(callback) {
  const newArr = [];
  for (let i = 0; i < this.length; i++) {
    if (i in this) { // 处理稀疏数组
      newArr[i] = callback(this[i], i, this);
    }
  }
  return newArr;
};
// 手动实现 reduce
Array.prototype.myReduce = function(callback, initialValue) {
  let acc = initialValue;
  let startIndex = 0;
  // 无 initialValue 时,acc 初始化为第一个元素
  if (initialValue === undefined) {
    if (this.length === 0) throw new TypeError('空数组无初始值');
    acc = this[0];
    startIndex = 1;
  }
  for (let i = startIndex; i < this.length; i++) {
    if (i in this) {
      acc = callback(acc, this[i], i, this);
    }
  }
  return acc;
};

总结

到此这篇关于JavaScript数组核心方法(附多场景示例)的文章就介绍到这了,更多相关JS数组核心方法内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • 微信小程序wx.previewImage预览图片实例详解

    微信小程序wx.previewImage预览图片实例详解

    下面通过实例代码给大家讲解了微信小程序wx.previewImage预览图片功能,需要的朋友可以参考下
    2017-12-12
  • js parseInt的陷阱分析小结

    js parseInt的陷阱分析小结

    js parseInt的陷阱分析小结,当第一个字符为0时,Js会把它看成一个8进制数字,其他8进制之外的字符都回被忽略掉。
    2011-03-03
  • javascript设计模式之中介者模式Mediator

    javascript设计模式之中介者模式Mediator

    这篇文章主要介绍了javascript设计模式之中介者模式Mediator,需要的朋友可以参考下
    2014-12-12
  • 移动端横屏的JS代码(beta)

    移动端横屏的JS代码(beta)

    这篇文章主要介绍了移动端横屏的JS代码(beta) 的相关资料,需要的朋友可以参考下
    2016-05-05
  • 能在网页中写字和能擦写的js程序

    能在网页中写字和能擦写的js程序

    从经典论坛发现的一个可以在网页中写字和有擦除功能的javascript代码
    2008-04-04
  • addEventListener()与removeEventListener()解析

    addEventListener()与removeEventListener()解析

    这篇文章主要为大家详细介绍了addEventListener()与removeEventListener(),用于处理指定和删除事件处理程序操作,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2017-04-04
  • JS 实现随机验证码功能

    JS 实现随机验证码功能

    验证码验证是网页常出现的一个验证点,所谓验证码类型有很多,下面代码只是实现一个简单的验证功能,需要的朋友参考下
    2017-02-02
  • js数据类型以及其判断方法实例

    js数据类型以及其判断方法实例

    这篇文章主要给大家介绍了关于js数据类型以及其判断方法的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2021-03-03
  • javascript开发随笔一 preventDefault的必要

    javascript开发随笔一 preventDefault的必要

    给a做按钮的click事件加preventDefault阻止浏览器的默认行为貌似是印象中必须的事情
    2011-11-11
  • TypeScript中如何实现类型安全的路由系统

    TypeScript中如何实现类型安全的路由系统

    本文讲述TypeScript如何实现类型安全的路由系统,路由类型结构、使用infer和Extract提取参数类型、定义路由配置类型、创建路由表、实现类型安全的导航和位置钩子等,使用React Router v6或Next.js App Router,结合zod进行查询参数验证,以实现类型安全的路由系统
    2025-10-10

最新评论