JS数组操作方法全景图,全网最全构建完整知识网络!js数组操作方法全集(实现筛选转换、随机排序洗牌算法、复杂数据处理统计等情景详解,附大量源码和易错点解析)

简介: 这些方法提供了对数组的全面操作,包括搜索、遍历、转换和聚合等。通过分为原地操作方法、非原地操作方法和其他方法便于您理解和记忆,并熟悉他们各自的使用方法与使用范围。详细的案例与进阶使用,方便您理解数组操作的底层原理。链式调用的几个案例,让您玩转数组操作。 只有锻炼思维才能可持续地解决问题,只有思维才是真正值得学习和分享的核心要素。如果这篇博客能给您带来一点帮助,麻烦您点个赞支持一下,还可以收藏起来以备不时之需,有疑问和错误欢迎在评论区指出~

部分链接无法正常显示,可移步到:https://opengms-watermelo.blog.csdn.net/article/details/143762021查看详细内容

作者:watermelo37

涉及领域:Vue、SpingBoot、Docker、LLM、python等

---------------------------------------------------------------------

温柔地对待温柔的人,包容的三观就是最大的温柔。

---------------------------------------------------------------------

image.gif 编辑

JS数组操作方法全景图,全网最全构建完整知识网络!js数组操作方法全集(实现筛选转换、随机排序洗牌算法、复杂数据处理统计等情景详解,附大量源码和易错点解析)

image.gif 编辑

一、写在前面

       为什么说史上最全?因为真的是史上最全!本文有如下几点优势:

  1. 收录数组常用方法,并且足够全,网上很多全集都只有17-19种方法,并且存在互相抄袭借鉴的情况,导致有些同样常见的方法广泛的没有收录,让人摸不着头脑,浪费时间,知识网络构建不全面。
  2. 为了便于您更好的理解,本身没有将所有数组方法一股脑儿的摆出来,而是将他们分为“修改原数组”、“生成新数组”、“其他(不修改也不新增数组)”,方便分类和记忆。
  3. 为了优化阅读体验,本文中每个方法都只提供了一种最基础最简单最易懂的案例。但是所有稍微复杂一点的方法都有详细的博文介绍,不但有详细的原理介绍,还有进阶复杂的应用与实战案例,所有博文都是我个人精心准备撰写的,内容详细,结构清晰,供您查阅。
  4. 围绕这些重点,我精心针对各个知识点单独撰写了十几篇博文,从简单到高级,从理论到应用,从调用到底层逻辑。

       综上所述,本文不只是查漏补缺的分享,更是一个详细周密的JS数组方法字典,您要是有长期的前端开发需求或是未来打算深耕前端技术,欢迎您收藏以备不时之需。要是能点个赞就更好了。

二、原地操作方法(修改原数组)

       特点:这些方法直接对原数组进行修改,返回值可能是处理结果,也可能是操作后数组的长度。适用于需要对原数组就地操作的场景。

1、Array.reverse()

       反转数组中的元素,没什么好说的,一看就懂。

let arr = [1, 2, 3];
arr.reverse();
console.log(arr); // [3, 2, 1]

image.gif

2、Array.sort()

       对数组元素进行排序,默认情况下sort() 会将数组元素转换为字符串并按字典序排序。

易错点解析:

       如果直接比较数字数组排序,会出现"10"<"6"之类的情况,因为在字符串中是先比较第一位,再往后逐步推进,“1”在字符串中在“6”前面,"1"<"6",就不会再比较第二位了,所以"10"<"6"。

let arr = [3, 1, 2];
arr.sort(); // 默认按字典序排序
console.log(arr); // [1, 2, 3]
arr.sort((a, b) => b - a); // 降序排序
console.log(arr); // [3, 2, 1]

image.gif

        Array.sort()方法最关键的是比较函数的书写,我专门写了一篇详细介绍的博文,您可以点击以下链接查阅:

3、Array.find()和Array.findIndex()

       Array.find()返回数组中满足条件的第一个元素。Array.findIndex()返回数组中满足条件的第一个元素的索引。

       既然是返回元素,为什么会放到“修改原数组”这个分类中呢?因为Array.find()这个方法普遍用来修改元素为对象的数组中特定的元素。如果只是需要确定数组中有没有某个值,用Array.includes()更方便,需要获取数组中有哪些满足条件的元素,也是用Array.filter()更适合。

       所以Array.find()的根本用途,就是找到数组元素中满足条件的第一个对象或者数组,并修改它。Array.find()返回的元素是原数组对应元素的引用,修改返回值就会直接修改原数组中对应元素的值。

       Array.find()也是数组操作方法中,唯一一个返回原数组元素引用的方法。这个特点也就证明了它就是干这个的。

const users = [
  { id: 1, name: 'Alice', role: 'user' },
  { id: 2, name: 'Bob', role: 'user' },
];
const bobUpdate = users.find(user => user.name === "Bob");
bobUpdate.role = 'admin'
console.log(users);
// 输出:[{ id: 1, name: 'Alice', role: 'user' }, { id: 2, name: 'Bob', role: 'admin' }]

image.gif

        详细介绍请移步:

4、Array.fill()

       用一个固定值填充数组的部分或全部元素,用的也不多,一般用于固定长度数组初始化,比如全部填充数组或字符串,以免遍历的时候因为元素类型不统一报错。

let arr = [1, 2, 3];
arr.fill(0); // 全部填充0
console.log(arr); // [0, 0, 0]
let arr = [1, 2, 3];
arr.fill(0, 1); // 从索引1开始填充
console.log(arr); // [1, 0, 0]

image.gif

5、Array.splice()

       添加或删除数组中的元素,常用来删除,如果第二个参数为0,那就可以仅添加。

let arr = [1, 2, 3];
arr.splice(1, 1, 4, 5); // 从索引1开始删除1个元素,插入4和5
console.log(arr); // [1, 4, 5, 3]

image.gif

6、Array.pop()

       移除数组的最后一个元素,并返回该元素,常用于栈操作(后进先出)。

let arr = [1, 2, 3];
let last = arr.pop();
console.log(last); // 3
console.log(arr);  // [1, 2]

image.gif

7、Array.push()

       添加一个或多个元素到数组的末尾,并返回新的长度。这个非常常用,用来添加元素到数组中。

let arr = [1, 2];
let len = arr.push(3, 4);
console.log(len); // 4
console.log(arr); // [1, 2, 3, 4]

image.gif

8、Array.shift()

       移除数组的第一个元素,并返回该元素。适用于队列操作(先进先出)。

let arr = [1, 2, 3];
let first = arr.shift();
console.log(first); // 1
console.log(arr);   // [2, 3]

image.gif

9、Array.unshift()

       在数组的开头添加一个或多个元素,并返回新的长度。用于动态更新队列前部数据。

let arr = [2, 3];
let len = arr.unshift(1);
console.log(len); // 3
console.log(arr); // [1, 2, 3]

image.gif

二、非原地操作方法(不修改原数组)

      特点:这些方法返回一个新数组或值,保持原数组不变,非常适合在函数式编程中使用

1、Array.concat()

       合并两个或多个数组,并返回新数组。常用于数组拼接,确保原数组不受影响。

let arr1 = [1, 2];
let arr2 = [3, 4];
let newArr = arr1.concat(arr2);
console.log(newArr); // [1, 2, 3, 4]

image.gif

2、Array.slice()

       提取原数组的子数组,并返回新数组,提取指定范围的元素,而不影响原数组。

       请注意,接受两个参数分别为起始下标与终止下标,起始下标包括在新数组中,但是终止下标对应的元素不在新数组中。(即集合中的左闭右开)

let arr = [1, 2, 3, 4];
let subArr = arr.slice(1, 3);
console.log(subArr); // [2, 3]

image.gif

3、Array.filter()

       创建一个新数组,包含通过测试的所有元素,常用于筛选数据

let arr = [1, 2, 3, 4];
let evens = arr.filter(n => n % 2 === 0);
console.log(evens); // [2, 4]

image.gif

        详情请移步:

4、Array.map()

       创建一个新数组,其结果是原数组每个元素调用提供的函数后的值,用于数据的逐项转换

let arr = [1, 2, 3];
let squared = arr.map(x => x ** 2);
console.log(squared); // [1, 4, 9]
console.log(arr);     // [1, 2, 3](原数组不变)

image.gif

Tips:map()和forEach()的区别:

       核心就在于forEach()没有返回值,常用于执行数据的副作用,比如打印某个内容,或者找到满足要求的内容并执行某些操作(forEach() + if 但这种情形不一定有find好用)等;而map()虽然同样是遍历,但是会返回一个新的数组。

       forEach()主要功能就是打印,其他功能基本都能用更直接的数组操作方法替代,优点是对初学者特别友好,因为forEach可以用来实现其他数组操作方法(遍历本质就是穷举,理论上可以实现任何数组操作,包括排序),减少了初期学习的记忆成本。

       map()的核心在于会返回每个元素调用提供的函数后的值形成一个新数组,常用于数据转换,但依然可以不接收返回值从而实现forEach()的效果(只能执行副作用,不能用于修改原数组)。

       到这里您可以发现,由于js是一门弱类型语言,语法极为灵活,所以很多不同的数组操作方法都可以通过微调来实现相同的功能。丰富的数组操作方法一方面提升了编码效率,另一方面可以起到操作语义化的效果,便于代码阅读和长期维护。

        详情请移步:

5、Array.flat() 和 flatMap()

       将多维数组展平成一维数组,flat():将嵌套数组展平成一维数组,支持指定展开的深度,flatMap():先对数组进行映射操作,再展平结果,等效于 map() 加 flat() 的组合,用于处理嵌套数组或复杂结构。

let arr = [1, [2, [3, [4]]]];
console.log(arr.flat(2)); // [1, 2, 3, [4]]
let words = ["hello world", "foo bar"];
let flattened = words.flatMap(str => str.split(" "));
console.log(flattened); // ["hello", "world", "foo", "bar"]

image.gif

        详情请移步:

三、其他方法

       还有一些其他方法,它们不直接修改数组,也不返回新数组,但提供了额外的功能:

1、Array.includes()

       判断数组是否包含某个元素,根据情况返回 true 或 false,可用于快速验证数组中的某个值是否存在。

let arr = [1, 2, 3];
console.log(arr.includes(2)); // true
console.log(arr.includes(4)); // false

image.gif

        详情请移步:

2、Array.forEach()

       对数组中的每个元素执行一次提供的函数,没有返回值,常用于遍历数组进行操作,但不适合需要返回值的场景。

let arr = [1, 2, 3];
arr.forEach(x => console.log(x * 2)); // 输出:2 4 6

image.gif

Tips:map()和forEach()的区别:

       核心就在于forEach()没有返回值,常用于执行数据的副作用,比如打印某个内容,或者找到满足要求的内容并执行某些操作(forEach() + if 但这种情形不一定有find好用)等;而map()虽然同样是遍历,但是会返回一个新的数组。

       forEach()主要功能就是打印,其他功能基本都能用更直接的数组操作方法替代,优点是对初学者特别友好,因为forEach可以用来实现其他数组操作方法(遍历本质就是穷举,理论上可以实现任何数组操作,包括排序),减少了初期学习的记忆成本。

       map()的核心在于会返回每个元素调用提供的函数后的值形成一个新数组,常用于数据转换,但依然可以不接收返回值从而实现forEach()的效果(只能执行副作用,不能用于修改原数组)。

       到这里您可以发现,由于js是一门弱类型语言,语法极为灵活,所以很多不同的数组操作方法都可以通过微调来实现相同的功能。丰富的数组操作方法一方面提升了编码效率,另一方面可以起到操作语义化的效果,便于代码阅读和长期维护。

        详情请移步:

3、Array.some()

       测试数组中的元素是否至少有一个满足条件,返回布尔值。

       高阶:本质是只要返回true就会立马结束遍历,如果修改回调函数,在某个元素不满足条件时返回true,也会直接结束遍历,并不一定非要“某个元素满足条件”。

let arr = [1, 2, 3];
console.log(arr.some(x => x > 2)); // true
console.log(arr.some(x => x > 3)); // false
let i = 0
let result = arr.some((num) => {
    i++;
    if(num!=1) return true
})
console.log(i , result ); // 2 true

image.gif

        详情请移步:

4、Array.every()

       测试数组中的所有元素是否都满足条件。

       高阶:本质是只要返回false就会立马结束遍历,如果修改回调函数,使其在某种情况下直接返回false,就会直接终止遍历。该方法与Array.some()是互斥的,可以参考Array.some()的例子。

let arr = [1, 2, 3];
console.log(arr.every(x => x > 0)); // true

image.gif

         详情请移步:

5、Array.reduce() 和 reduceRight()

       对数组中的值进行汇总、合并操作,最终计算为单个返回值,reduce():从左到右执行归约操作,reduceRight():从右到左执行归约操作,常用于求和、统计等聚合计算。

let arr = [1, 2, 3, 4];
let sum = arr.reduce((acc, curr) => acc + curr, 0);
console.log(sum); // 10
let reversedSum = arr.reduceRight((acc, curr) => acc + curr, 0);
console.log(reversedSum); // 10

image.gif

        这个相对复杂,如果您对这个方法比较陌生,请直接移步到具体的博客内容:

6、Array.indexOf()

       返回在数组中可以找到一个给定元素的第一个索引,如果不存在,则返回 -1,用来查找某个元素在数组中的位置。

let arr = [1, 2, 3, 2];
console.log(arr.indexOf(2)); // 1

image.gif

7、Array.lastIndexOf()

       返回在数组中可以找到一个给定元素的最后一个索引,如果不存在,则返回 -1,用来查找某个元素在数组中的位置。

let arr = [1, 2, 3, 2];
console.log(arr.lastIndexOf(2)); // 3

image.gif

8、Array.keys()

       返回一个包含数组中每个索引的键的迭代器。

let arr = ["a", "b", "c"];
for (let key of arr.keys()) {
    console.log(key); // 输出:0 1 2
}

image.gif

9、Array.values()

       返回一个迭代器,它允许迭代数组的值。

let arr = ["a", "b", "c"];
for (let value of arr.values()) {
    console.log(value); // 输出:a b c
}

image.gif

10、Array.entries()

       返回一个迭代器,它允许迭代数组的索引和值。

let arr = ["a", "b", "c"];
for (let [key, value] of arr.entries()) {
    console.log(key, value); // 输出:0 a, 1 b, 2 c
}

image.gif

四、常用的组合链式调用方法

1、数据筛选和转换:filter() + map()

       这种组合非常常见,首先通过 filter() 筛选出符合条件的元素,然后通过 map() 对筛选后的数据进行转换。

       案例:筛选出分数大于 60 的学生,并将其分数转换为百分制。

let students = [
    { name: "Alice", score: 45 },
    { name: "Bob", score: 85 },
    { name: "Charlie", score: 62 },
    { name: "David", score: 30 },
];
// 筛选分数大于 60 的学生,并将分数转换为百分制
let passedStudents = students
    .filter(student => student.score > 60)
    .map(student => ({ name: student.name, percentage: student.score + "%" }));
console.log(passedStudents);
// 输出:
// [
//   { name: 'Bob', percentage: '85%' },
//   { name: 'Charlie', percentage: '62%' }
// ]

image.gif

2、复杂数据统计:reduce() + 自定义逻辑

       reduce() 是数据统计和聚合的强大工具,可以根据自定义逻辑进行复杂计算。

       案例:统计订单总金额和每种商品的数量。

let orders = [
    { product: "Apple", quantity: 2, price: 3 },
    { product: "Banana", quantity: 3, price: 2 },
    { product: "Apple", quantity: 1, price: 3 },
    { product: "Orange", quantity: 5, price: 4 },
];
// 使用 reduce 汇总
let summary = orders.reduce((acc, order) => {
    acc.totalAmount += order.quantity * order.price; // 累加总金额
    acc.productCount[order.product] = 
        (acc.productCount[order.product] || 0) + order.quantity; // 统计每种商品的数量
    return acc;
}, { totalAmount: 0, productCount: {} });
console.log(summary);
// 输出:
// {
//   totalAmount: 35,
//   productCount: { Apple: 3, Banana: 3, Orange: 5 }
// }

image.gif

3、嵌套数组处理:flat() + map()

       当数据存在嵌套结构时,可以用 flat() 将其展平,再用 map() 进行转换或处理。

       案例:将嵌套的课程成绩展平并标记成绩是否及格。

let courses = [
    [
        { student: "Alice", score: 45 },
        { student: "Bob", score: 85 }
    ],
    [
        { student: "Charlie", score: 62 },
        { student: "David", score: 30 }
    ]
];
// 展平嵌套数组并标记成绩是否及格
let processedCourses = courses
    .flat() // 展平成一维数组
    .map(course => ({
        student: course.student,
        score: course.score,
        passed: course.score >= 60
    }));
console.log(processedCourses);
// 输出:
// [
//   { student: 'Alice', score: 45, passed: false },
//   { student: 'Bob', score: 85, passed: true },
//   { student: 'Charlie', score: 62, passed: true },
//   { student: 'David', score: 30, passed: false }
// ]

image.gif

4、数组去重:5种情形14种方法

       Set 是一种数据结构,可以快速实现去重。将数组转换为 Set,然后再转换回数组即可完成去重操作。

let numbers = [1, 2, 2, 3, 4, 4, 5];
// 使用 Set 去重
let uniqueNumbers = [...new Set(numbers)];
console.log(uniqueNumbers); 
// 输出:[1, 2, 3, 4, 5]
// 示例:对对象数组按某个字段去重
let items = [
    { id: 1, name: "Apple" },
    { id: 2, name: "Banana" },
    { id: 1, name: "Apple" },
    { id: 3, name: "Orange" }
];
// 按 id 去重
let uniqueItems = Array.from(new Map(items.map(item => [item.id, item])).values());
console.log(uniqueItems);
// 输出:
// [
//   { id: 1, name: "Apple" },
//   { id: 2, name: "Banana" },
//   { id: 3, name: "Orange" }
// ]

image.gif

       这只是一个简单的案例,实际上本人将数组去重分为:数值类去重、引用类去重和混合数组去重,引用类去重又包括去除完全重复元素、去除完全重复元素的特殊情况、去除部分重复的对象元素三种情况,一共是五种情形,涉及到14种不同的去重方法,让您一次性看个够,享受算法的魅力:

五、总结

       这些方法提供了对数组的全面操作,包括搜索、遍历、转换和聚合等。通过分为原地操作方法、非原地操作方法和其他方法便于您理解和记忆,并熟悉他们各自的使用方法与使用范围。详细的案例与进阶使用,方便您理解数组操作的底层原理。链式调用的几个案例,让您玩转数组操作。

        只有锻炼思维才能可持续地解决问题,只有思维才是真正值得学习和分享的核心要素。如果这篇博客能给您带来一点帮助,麻烦您点个赞支持一下,还可以收藏起来以备不时之需,有疑问和错误欢迎在评论区指出~

       其他热门文章,请关注:

       极致的灵活度满足工程美学:用Vue Flow绘制一个完美流程图

       你真的会使用Vue3的onMounted钩子函数吗?Vue3中onMounted的用法详解

       通过array.filter()实现数组的数据筛选、数据清洗和链式调用

       通过Array.sort() 实现多字段排序、排序稳定性、随机排序洗牌算法、优化排序性能

       TreeSize:免费的磁盘清理与管理神器,解决C盘爆满的燃眉之急

       通过MongoDB Atlas 实现语义搜索与 RAG——迈向AI的搜索机制

       el-table实现动态数据的实时排序,一篇文章讲清楚elementui的表格排序功能

       MutationObserver详解+案例——深入理解 JavaScript 中的 MutationObserver

       Dockerfile全面指南:从基础到进阶,掌握容器化构建的核心工具

       在线编程实现!如何在Java后端通过DockerClient操作Docker生成python环境

       深入理解 JavaScript 中的 Array.find() 方法:原理、性能优势与实用案例详解

       干货含源码!如何用Java后端操作Docker(命令行篇)

相关文章
|
1月前
|
机器学习/深度学习 PyTorch TensorFlow
卷积神经网络深度解析:从基础原理到实战应用的完整指南
蒋星熠Jaxonic,深度学习探索者。深耕TensorFlow与PyTorch,分享框架对比、性能优化与实战经验,助力技术进阶。
|
2月前
|
JavaScript 前端开发 开发者
Nest.js控制器深度解析:路由与请求处理的高级特性
以上就是对 NestJS 控制层高级特性深度解析:从基本概念到异步支持再到更复杂场景下拦截其与管道等功能性组件运用都有所涉及,希望能够帮助开发者更好地理解和运用 NestJS 进行高效开发工作。
318 15
|
2月前
|
JavaScript 前端开发 IDE
TypeScript vs. JavaScript:技术对比与核心差异解析
TypeScript 作为 JavaScript 的超集,通过静态类型系统、编译时错误检测和强大的工具链支持,显著提升代码质量与可维护性,尤其适用于中大型项目和团队协作。相较之下,JavaScript 更灵活,适合快速原型开发。本文从类型系统、错误检测、工具支持等多维度对比两者差异,并提供技术选型建议,助力开发者合理选择。
585 1
|
2月前
|
机器学习/深度学习 人工智能 算法
卷积神经网络深度解析:从基础原理到实战应用的完整指南
蒋星熠Jaxonic带你深入卷积神经网络(CNN)核心技术,从生物启发到数学原理,详解ResNet、注意力机制与模型优化,探索视觉智能的演进之路。
373 11
|
2月前
|
安全 网络性能优化 网络虚拟化
网络交换机分类与功能解析
接入交换机(ASW)连接终端设备,提供高密度端口与基础安全策略;二层交换机(LSW)基于MAC地址转发数据,构成局域网基础;汇聚交换机(DSW)聚合流量并实施VLAN路由、QoS等高级策略;核心交换机(CSW)作为网络骨干,具备高性能、高可靠性的高速转发能力;中间交换机(ISW)可指汇聚层设备或刀片服务器内交换模块。典型流量路径为:终端→ASW→DSW/ISW→CSW,分层架构提升网络扩展性与管理效率。(238字)
753 0
|
监控 Java 应用服务中间件
高级java面试---spring.factories文件的解析源码API机制
【11月更文挑战第20天】Spring Boot是一个用于快速构建基于Spring框架的应用程序的开源框架。它通过自动配置、起步依赖和内嵌服务器等特性,极大地简化了Spring应用的开发和部署过程。本文将深入探讨Spring Boot的背景历史、业务场景、功能点以及底层原理,并通过Java代码手写模拟Spring Boot的启动过程,特别是spring.factories文件的解析源码API机制。
341 2
|
8月前
|
算法 测试技术 C语言
深入理解HTTP/2:nghttp2库源码解析及客户端实现示例
通过解析nghttp2库的源码和实现一个简单的HTTP/2客户端示例,本文详细介绍了HTTP/2的关键特性和nghttp2的核心实现。了解这些内容可以帮助开发者更好地理解HTTP/2协议,提高Web应用的性能和用户体验。对于实际开发中的应用,可以根据需要进一步优化和扩展代码,以满足具体需求。
815 29
|
8月前
|
前端开发 数据安全/隐私保护 CDN
二次元聚合短视频解析去水印系统源码
二次元聚合短视频解析去水印系统源码
322 4
|
8月前
|
移动开发 前端开发 JavaScript
从入门到精通:H5游戏源码开发技术全解析与未来趋势洞察
H5游戏凭借其跨平台、易传播和开发成本低的优势,近年来发展迅猛。接下来,让我们深入了解 H5 游戏源码开发的技术教程以及未来的发展趋势。
|
8月前
|
存储 前端开发 JavaScript
在线教育网课系统源码开发指南:功能设计与技术实现深度解析
在线教育网课系统是近年来发展迅猛的教育形式的核心载体,具备用户管理、课程管理、教学互动、学习评估等功能。本文从功能和技术两方面解析其源码开发,涵盖前端(HTML5、CSS3、JavaScript等)、后端(Java、Python等)、流媒体及云计算技术,并强调安全性、稳定性和用户体验的重要性。

热门文章

最新文章

推荐镜像

更多
  • DNS