JavaScript之数组方法详解

JavaScript之数组方法详解

    • 一、数组的创建与基础特性
      • 1.1 数组的创建方式
      • 1.2 数组的核心特性
    • 二、修改原数组的方法
      • 2.1 添加/删除元素
        • 2.1.1 `push()`:尾部添加元素
        • 2.1.2 `pop()`:尾部删除元素
        • 2.1.3 `unshift()`:头部添加元素
        • 2.1.4 `shift()`:头部删除元素
        • 2.1.5 `splice()`:指定位置添加/删除
      • 2.2 排序与反转
        • 2.2.1 `reverse()`:反转数组
        • 2.2.2 `sort()`:排序数组
    • 三、不修改原数组的方法
      • 3.1 数组截取与合并
        • 3.1.1 `slice()`:截取子数组
        • 3.1.2 `concat()`:合并数组
      • 3.2 元素查找
        • 3.2.1 `indexOf()`与`lastIndexOf()`:查找索引
        • 3.2.2 `includes()`:判断元素是否存在
        • 3.2.3 `find()`与`findIndex()`:查找符合条件的元素
      • 3.3 数组转换
        • 3.3.1 `join()`:数组转字符串
        • 3.3.2 `toString()`:数组转字符串(简化版)
    • 四、遍历与迭代方法
      • 4.1 基础遍历
        • 4.1.1 `forEach()`:遍历元素
      • 4.2 映射与过滤
        • 4.2.1 `map()`:映射新数组
        • 4.2.2 `filter()`:过滤元素
      • 4.3 聚合与检测
        • 4.3.1 `reduce()`:累加计算
        • 4.3.2 `every()`与`some()`:条件检测
    • 五、方法对比与最佳实践
      • 5.1 方法选择指南
      • 5.2 性能与注意事项
    • 六、常见问题与避坑指南
      • 6.1 `sort()`的默认排序陷阱
      • 6.2 `indexOf()`无法识别`NaN`
      • 6.3 `map()`返回新数组的长度不变

数组是JavaScript中最常用的数据结构之一,掌握数组方法是高效处理数据的基础,本文我将系统梳理JavaScript数组的常用方法,从基础的添加删除到复杂的遍历转换,并结合实例解析每种方法的用法、特性及适用场景,帮你彻底搞懂数组操作的核心技巧。

一、数组的创建与基础特性

在学习方法之前,先回顾数组的创建方式,这是后续操作的基础:

1.1 数组的创建方式

// 1. 字面量方式(最常用)
const arr1 = [1, 2, 3];// 2. 构造函数方式
const arr2 = new Array(3); // 创建长度为3的空数组([ , , ])
const arr3 = new Array(1, 2, 3); // 创建包含元素的数组([1,2,3])// 3. 静态方法创建(ES6+)
const arr4 = Array.of(1, 2, 3); // 类似字面量,避免new Array的歧义
const arr5 = Array.from([1, 2, 3], x => x * 2); // 从类数组/可迭代对象创建并映射([2,4,6])

1.2 数组的核心特性

  • 动态长度:数组长度可自动扩展(如arr.push(4)会增加长度)
  • 元素类型不限:可包含数字、字符串、对象等任意类型
  • 索引从0开始:通过arr[index]访问元素

二、修改原数组的方法

这类方法会直接改变原数组,操作时需注意对原数据的影响。

2.1 添加/删除元素

2.1.1 push():尾部添加元素
const fruits = ['apple', 'banana'];
const newLength = fruits.push('orange', 'grape'); // 添加多个元素
console.log(fruits); // ['apple', 'banana', 'orange', 'grape']
console.log(newLength); // 4(返回新长度)

特性:接受任意数量参数,添加到数组末尾,返回新长度。

2.1.2 pop():尾部删除元素
const lastFruit = fruits.pop(); // 删除最后一个元素
console.log(fruits); // ['apple', 'banana', 'orange']
console.log(lastFruit); // 'grape'(返回被删除的元素)

特性:无参数,删除最后一个元素,返回被删除元素。

2.1.3 unshift():头部添加元素
const newLength = fruits.unshift('mango'); // 头部添加
console.log(fruits); // ['mango', 'apple', 'banana', 'orange']
console.log(newLength); // 4(返回新长度)

特性:接受任意数量参数,添加到数组头部,返回新长度(性能比push()差,因需移动所有元素)。

2.1.4 shift():头部删除元素
const firstFruit = fruits.shift(); // 删除第一个元素
console.log(fruits); // ['apple', 'banana', 'orange']
console.log(firstFruit); // 'mango'(返回被删除元素)

特性:无参数,删除第一个元素,返回被删除元素(性能较差,同unshift())。

2.1.5 splice():指定位置添加/删除
const numbers = [1, 2, 3, 4, 5];// 1. 删除:splice(起始索引, 删除数量)
const deleted = numbers.splice(2, 2); // 从索引2开始删除2个元素
console.log(numbers); // [1, 2, 5]
console.log(deleted); // [3, 4](返回被删除元素数组)// 2. 添加:splice(起始索引, 0, 添加元素1, ...)
numbers.splice(2, 0, 3, 4); // 从索引2开始,删除0个,添加3和4
console.log(numbers); // [1, 2, 3, 4, 5](恢复原数组)// 3. 替换:splice(起始索引, 删除数量, 替换元素)
numbers.splice(1, 2, 'a', 'b'); // 从索引1删除2个,添加'a','b'
console.log(numbers); // [1, 'a', 'b', 4, 5]

特性:功能强大,可同时完成添加和删除,返回被删除元素数组(若未删除则返回空数组)。

2.2 排序与反转

2.2.1 reverse():反转数组
const arr = [1, 2, 3];
arr.reverse();
console.log(arr); // [3, 2, 1]

特性:直接反转原数组,返回反转后的数组(与原数组引用相同)。

2.2.2 sort():排序数组
// 1. 默认排序(按字符串Unicode码点,可能不符合预期)
const nums = [10, 2, 23];
nums.sort(); 
console.log(nums); // [10, 2, 23](错误排序,因'10'在'2'前)// 2. 数值升序排序(传入比较函数)
nums.sort((a, b) => a - b); 
console.log(nums); // [2, 10, 23]// 3. 数值降序排序
nums.sort((a, b) => b - a); 
console.log(nums); // [23, 10, 2]// 4. 对象数组排序(按age属性升序)
const users = [{ name: 'Bob', age: 25 },{ name: 'Alice', age: 20 }
];
users.sort((a, b) => a.age - b.age);
console.log(users); // [Alice(20), Bob(25)]

特性:默认按字符串排序,需传入比较函数(a,b) => a - b(升序)或(a,b) => b - a(降序)实现数值排序;直接修改原数组,返回排序后的数组。

三、不修改原数组的方法

这类方法会返回新数组或其他结果,原数组保持不变,适合函数式编程。

3.1 数组截取与合并

3.1.1 slice():截取子数组
const arr = [1, 2, 3, 4, 5];// 1. slice(起始索引, 结束索引):含头不含尾
const sub1 = arr.slice(1, 4); // 从索引1到3(不包含4)
console.log(sub1); // [2, 3, 4]// 2. 省略结束索引:截取到末尾
const sub2 = arr.slice(2); // 从索引2到末尾
console.log(sub2); // [3, 4, 5]// 3. 负数索引:从末尾开始计算
const sub3 = arr.slice(-3, -1); // 从倒数第3到倒数第2(索引2和3)
console.log(sub3); // [3, 4]

特性:返回新数组(原数组不变),参数支持负数(表示从末尾开始),slice(0)可用于复制数组。

3.1.2 concat():合并数组
const arr1 = [1, 2];
const arr2 = [3, 4];
const arr3 = [5];// 合并多个数组
const merged = arr1.concat(arr2, arr3, 6); // 可添加非数组元素
console.log(merged); // [1, 2, 3, 4, 5, 6]
console.log(arr1); // [1, 2](原数组不变)

特性:合并多个数组或值,返回新数组(原数组不变),类似ES6的扩展运算符[...arr1, ...arr2]

3.2 元素查找

3.2.1 indexOf()lastIndexOf():查找索引
const fruits = ['apple', 'banana', 'apple', 'orange'];// indexOf(元素, 起始索引):从前往后找,返回首次出现的索引
console.log(fruits.indexOf('apple')); // 0
console.log(fruits.indexOf('apple', 1)); // 2(从索引1开始找)
console.log(fruits.indexOf('grape')); // -1(未找到)// lastIndexOf(元素):从后往前找,返回最后出现的索引
console.log(fruits.lastIndexOf('apple')); // 2

特性indexOf从头部开始,lastIndexOf从尾部开始;返回元素索引,未找到返回-1;使用严格相等(===)比较,无法查找引用类型元素。

3.2.2 includes():判断元素是否存在
const nums = [1, 2, 3, NaN];// 基础用法
console.log(nums.includes(2)); // true
console.log(nums.includes(5)); // false// 特殊:能识别NaN(indexOf不能)
console.log(nums.includes(NaN)); // true
console.log(nums.indexOf(NaN)); // -1(indexOf的缺陷)

特性:返回布尔值(是否包含元素),支持NaN判断(比indexOf更友好),第二个参数可指定起始索引。

3.2.3 find()findIndex():查找符合条件的元素
const users = [{ id: 1, name: 'Alice' },{ id: 2, name: 'Bob' },{ id: 3, name: 'Alice' }
];// find(回调函数):返回第一个符合条件的元素
const alice = users.find(user => user.name === 'Alice');
console.log(alice); // { id: 1, name: 'Alice' }// findIndex(回调函数):返回第一个符合条件的元素索引
const aliceIndex = users.findIndex(user => user.name === 'Alice');
console.log(aliceIndex); // 0// 未找到时
console.log(users.find(user => user.id === 10)); // undefined
console.log(users.findIndex(user => user.id === 10)); // -1

特性:接受回调函数(item, index, arr) => 条件,返回第一个符合条件的元素(find)或索引(findIndex);适合查找对象数组,支持复杂条件。

3.3 数组转换

3.3.1 join():数组转字符串
const arr = ['a', 'b', 'c'];// 1. 默认用逗号分隔
console.log(arr.join()); // "a,b,c"// 2. 指定分隔符
console.log(arr.join('-')); // "a-b-c"// 3. 空字符串分隔(拼接成连续字符串)
console.log(arr.join('')); // "abc"

特性:将数组元素拼接为字符串,返回字符串;与String.split()互为逆操作。

3.3.2 toString():数组转字符串(简化版)
const arr = [1, 2, 3];
console.log(arr.toString()); // "1,2,3"(等价于join())

特性:默认用逗号分隔,功能简单,不如join()灵活。

四、遍历与迭代方法

这类方法用于遍历数组并执行操作,是处理数组数据的核心工具。

4.1 基础遍历

4.1.1 forEach():遍历元素
const nums = [1, 2, 3];
let sum = 0;// forEach(回调函数):无返回值
nums.forEach((num, index, arr) => {sum += num;console.log(`索引${index}的值:${num}`);
});
console.log('总和:', sum); // 6

特性:无返回值(undefined),无法通过break中断遍历(需用try/catchreturn跳过当前元素);适合简单的遍历操作。

4.2 映射与过滤

4.2.1 map():映射新数组
const numbers = [1, 2, 3, 4];// map(回调函数):返回新数组(每个元素为回调返回值)
const doubled = numbers.map(num => num * 2);
console.log(doubled); // [2, 4, 6, 8]
console.log(numbers); // [1, 2, 3, 4](原数组不变)// 对象数组映射
const users = [{ name: 'A' }, { name: 'B' }];
const names = users.map(user => user.name);
console.log(names); // ['A', 'B']

特性:返回新数组(长度与原数组相同),原数组不变;适合数据转换(如从对象数组中提取特定属性)。

4.2.2 filter():过滤元素
const numbers = [1, 2, 3, 4, 5, 6];// filter(回调函数):返回符合条件的元素组成的新数组
const evens = numbers.filter(num => num % 2 === 0);
console.log(evens); // [2, 4, 6]// 对象数组过滤
const users = [{ name: 'A', age: 17 },{ name: 'B', age: 20 },{ name: 'C', age: 25 }
];
const adults = users.filter(user => user.age >= 18);
console.log(adults); // [B(20), C(25)]

特性:返回新数组(包含所有符合条件的元素),原数组不变;适合数据筛选。

4.3 聚合与检测

4.3.1 reduce():累加计算
const numbers = [1, 2, 3, 4];// reduce(回调函数, 初始值):返回累加结果
const sum = numbers.reduce((acc, num) => {return acc + num; // acc为累加器,num为当前元素
}, 0); // 初始值为0
console.log('总和:', sum); // 10// 计算数组中每个元素出现的次数
const fruits = ['apple', 'banana', 'apple'];
const count = fruits.reduce((acc, fruit) => {acc[fruit] = (acc[fruit] || 0) + 1;return acc;
}, {}); // 初始值为对象
console.log(count); // { apple: 2, banana: 1 }

特性:从左到右遍历,通过累加器acc聚合结果,功能强大(可实现summaxgroupBy等);reduceRight()从右到左遍历,用法类似。

4.3.2 every()some():条件检测
const scores = [80, 90, 75, 60];// every():所有元素都符合条件才返回true
const allPass = scores.every(score => score >= 60);
console.log(allPass); // true(所有分数≥60)// some():至少一个元素符合条件就返回true
const hasExcellent = scores.some(score => score >= 90);
console.log(hasExcellent); // true(有一个分数≥90)

特性every类似“逻辑与”(全满足),some类似“逻辑或”(有一个满足);返回布尔值,且会短路(every遇到不满足的元素立即返回falsesome遇到满足的立即返回true)。

五、方法对比与最佳实践

5.1 方法选择指南

需求场景推荐方法替代方法
尾部添加元素push()splice(arr.length, 0, x)
尾部删除元素pop()splice(arr.length-1, 1)
截取子数组slice()-
数组映射(转换)map()-
数组过滤filter()-
累加计算reduce()forEach()(较繁琐)
查找对象数组元素find()/findIndex()forEach()(需手动判断)
判断元素是否存在includes()indexOf() !== -1

5.2 性能与注意事项

  • 修改原数组 vs 返回新数组
    • 需保留原数组时,优先用slice()map()等不修改原数组的方法;
    • 频繁操作大型数组时,push()concat()性能更好(因concat()返回新数组)。
  • 遍历中断
    • forEach()无法用break中断,若需中断可改用for循环或some()(通过return true中断)。
  • 引用类型处理
    • 数组方法对对象元素的操作会影响原对象(因对象是引用传递):
    const users = [{ name: 'A' }];
    users.map(user => { user.age = 18; }); // 修改原对象
    console.log(users); // [{ name: 'A', age: 18 }]
    

六、常见问题与避坑指南

6.1 sort()的默认排序陷阱

const nums = [10, 2, 23];
nums.sort(); // 错误:按字符串排序,结果[10, 2, 23]
nums.sort((a, b) => a - b); // 正确:数值升序,结果[2, 10, 23]

解决方案:始终传入比较函数处理数值排序。

6.2 indexOf()无法识别NaN

const arr = [NaN];
console.log(arr.indexOf(NaN)); // -1(错误)
console.log(arr.includes(NaN)); // true(正确)

解决方案:判断NaN时用includes(),不用indexOf()

6.3 map()返回新数组的长度不变

const arr = [1, 2, 3];
const newArr = arr.map(num => {if (num > 1) return num * 2;// 未返回值时,默认返回undefined
});
console.log(newArr); // [undefined, 4, 6](长度仍为3)

解决方案map()适合“一对一”转换,若需过滤元素应配合filter()

const newArr = arr.filter(num => num > 1).map(num => num * 2); // [4, 6]

总结:数组方法的核心要点

  1. 区分修改与不修改原数组的方法,根据是否需要保留原数据选择;
  2. 遍历与转换方法map()filter()reduce())是处理复杂数据的核心,需熟练掌握;
  3. 查找方法中,find()适合对象数组,includes()适合简单元素判断;
  4. 注意方法的性能差异和特殊场景(如sort()的比较函数、includes()NaN的支持)。

若这篇内容帮到你,动动手指支持下!关注不迷路,干货持续输出!
ヾ(´∀ ˋ)ノヾ(´∀ ˋ)ノヾ(´∀ ˋ)ノヾ(´∀ ˋ)ノヾ(´∀ ˋ)ノ

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/web/88029.shtml
繁体地址,请注明出处:http://hk.pswp.cn/web/88029.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

品牌增长困局突围:大模型时代,AI 如何帮我的品牌少走弯路?

AI时代对企业战略的冲击与机遇 在当今瞬息万变的商业环境中,大模型的崛起正以前所未有的力量重塑着各行各业的竞争格局。传统的市场营销、品牌传播模式正在被颠覆,消费者获取信息、认知品牌的方式发生了根本性变化。如果说过去十年是“互联网”的时代&am…

从单体到微服务:Spring Cloud 开篇与微服务设计

一、单体架构的核心痛点与微服务化目标 1. 单体架构的致命缺陷问题表现后果可维护性差百万行代码耦合,修改一处需全量测试迭代周期长,创新停滞扩展性受限无法按模块独立扩缩容(如订单模块需扩容时,用户模块被迫一起扩容&#xff0…

篇二 OSI七层模型,TCP/IP四层模型,路由器与交换机原理

一 前言 本章节主要介绍OSI七层模型,TCP/IP四层模型划分,以及日常使用的路由器,交换机的一些基础知识 二 OSI 七层 OSI(Open Systems Interconnection Model)即开放式系统互联模型,是国际标准化组织提出的&…

【JavaSE面试篇】Java集合部分高频八股汇总

目录 概念 1. 说说Java中的集合? 2. Java中的线程安全的集合有什么? 3. Collections和Collection的区别? 4. 集合遍历的方法有哪些? List 5. 讲一下java里面list的几种实现,几种实现有什么不同? 6.…

利用低空无人机影像进行树种实例分割

在本项先导研究中,我们开发了一个基于低空无人机影像的本地树种机器学习实例分割模型,用于生态调查。该实例分割包括单株树冠的描绘和树种的分类。我们利用无人机影像对20个树种及其对应的学名进行了训练,并收集了这些树种的学名用于机器学习。为了评估该机器学习模型的准确…

二、Flutter基础

目录1. 什么是Widget?Flutter中的Widget分为哪几类?2. StatelessWidget和StatefulWidget的区别3. StatefulWidget生命周期4. 什么是BuildContext?5. 如何优化Widget重建?6. Flutter布局机制7. Row/Column的主轴和交叉轴8. Expande…

设计模式笔记_创建型_建造者模式

1. 建造者模式介绍 建造者模式是一种创建型设计模式,旨在通过将复杂对象的构建过程与其表示分离,使得同样的构建过程可以创建不同的表示。它通常用于构造步骤固定但具体实现可能变化的对象。 1.1 功能: 封装复杂对象的创建过程:适…

【ROS2 自动驾驶学习】03-ROS2常用命令

目录 1. ros2 pkg list 2. ros2 node list 3. ros2 node info 节点名称 4. ros2 topic list 5. ros2 topic info 话题名 6. ros2 topic type 话题名 7. ros2 topic find 消息类型 8. ros2 service list 9. ros2 service type 服务名称 10. ros2 service find 服…

MyBatis-Plus:提升数据库操作效率的利器

在Java开发中,MyBatis是一个非常流行的持久层框架,它简化了数据库操作,提供了灵活的SQL映射功能。然而,随着项目规模的扩大和业务复杂度的增加,开发者需要更高效、更便捷的方式来处理数据库操作。MyBatis-Plus应运而生…

App爬虫实战篇-以华为真机手机爬取集换社的app为例

前言 在开始学习这篇文章之前,建议你先按照之前2篇文章(App爬虫工具篇-Appium安装和App爬虫工具篇-appium配置),配置必要的环境,才可以继续完成本章节内容。 电脑连接手机 可以通过usb连接电脑。如果通过adb devices命令,发现没有连接上,就需要手动配置一些信息 华为…

Vue3组合式API应用:状态共享与逻辑复用最佳实践

Vue3组合式API应用:状态共享与逻辑复用最佳实践 在Vue3中,组合式API的引入为我们提供了一种全新的方式来编写Vue组件,并有效地解决了混入和繁琐逻辑复用的问题。本文将为您介绍如何在Vue3中使用组合式API来实现状态共享与逻辑复用的最佳实践&…

在linux 上使用tcpdump监听http 端口的报文并分析

这里写目录标题 1. 使用 tcpdump(原始报文捕获)观察:报文翻译与分析(按行解释)第一段:客户端请求报文HTTP 请求头JSON 请求体第二段:服务器响应报文HTTP 响应头响应体关键问题分析在 Linux 上监听 HTTP 端口的报文,有多种工具可以实现。以下是几种常用方法的详细说明:…

XSStrike 进行 XSS 漏洞测试

XSStrike 是一个功能强大的 XSS 漏洞测试工具,专为检测、验证和利用反射型、存储型、DOM型 XSS 漏洞而设计,适合配合手工测试,也可用于自动化发现。 🛠️ 1. 安装 XSStrike 确保系统中有 Python3 和 git: git clone ht…

any实现(基于LLVM中libcxx实现分析)

本文根据LLVM中libcxx的实现,分析了std::any和std::variant的具体实现。 1 简介 在 C17 标准中,std::any提供了一种类型安全的方式来存储任意类型的值。它使用类型擦除(type erasure)技术实现,使得一个对象可以包含任…

网安系列【13】之渗透测试:前期信息收集

文章目录 前期信息收集信息收集的分类信息收集的内容域名信息收集Whois备案信息whois反查SSL证书查询域名收集工具IP收集CDN信息收集CDN判断CDN绕过 端口信息收集常见端口介绍FTP-21SSH-22WWW-80NetBlOSSessionService-139/445MySQL-3306RDP-3389Redis-6379Tomcat-8080 端口扫描…

自动驾驶传感器的标定与数据融合

目录 IMU的标定 相机的标定 激光雷达和组合惯导标定 相机和激光雷达标定 传感器数据融合 多传感器融合数据处理 传感器数据融合算法 环境感知与预测 应用实例——车道线识别 应用实例——车辆行人识别 应用实例——交通标志识别 定位系统 基于惯性导航仪的定位技术…

27.移除元素(快慢指针)

给你一个数组 nums 和一个值 val,你需要 原地 移除所有数值等于 val 的元素。元素的顺序可能发生改变。然后返回 nums 中与 val 不同的元素的数量。 假设 nums 中不等于 val 的元素数量为 k,要通过此题,您需要执行以下操作: 更改…

Spring AI:ETL Pipeline

提取、转换和加载(ETL)框架是检索增强生成(RAG)用例中数据处理的支柱。ETL管道协调从原始数据源到结构化向量存储的流程,确保数据以最佳格式供AI模型检索。RAG用例是文本,通过从数据体中检索相关信息来增强…

26.安卓逆向2-frida hook技术-解密响应

免责声明:内容仅供学习参考,请合法利用知识,禁止进行违法犯罪活动! 内容参考于:图灵Python学院 工具下载: 链接:https://pan.baidu.com/s/1bb8NhJc9eTuLzQr39lF55Q?pwdzy89 提取码&#xff1…

人工智能与人工智障———仙盟创梦IDE

<!-- 桌面导航 -->&#x3C;nav class&#x22;hidden md:flex items-center space-x-8&#x22;&#x3E;&#x3C;a href&#x22;#home&#x22; class&#x22;nav-link text-gray-700 hover:text-primary font-medium&#x22;&#x3E;&#x9996;&…