forEach如何修改原数组和sort排序经典场景

forEach() 介绍

代码举例:

  1. let myArr = [王一, 王二, 王三];
  2. myArr.forEach((item, index, arr) => {
  3. console.log(item: + item);
  4. console.log(index: + index);
  5. console.log(arr: + JSON.stringify(arr));
  6. });

打印结果:

  1. item:王一
  2. index:0
  3. arr:["王一","王二","王三"]
  4. ----------
  5. item:王二
  6. index:1
  7. arr:["王一","王二","王三"]
  8. ----------
  9. item:王三
  10. index:2
  11. arr:["王一","王二","王三"]
  12. ----------

注意:forEach() 没有返回值。也可以理解成:forEach() 的返回值是 undefined

let tempArry = myArr.forEach() 这种方式接收是没有意义的

forEach() 能不能改变原数组?

forEach() 能不能改变原数组?关于这个问题,大部分人会搞错。我们来看看下面的代码

1、数组的元素是基本数据类型:(无法改变原数组)

  1. let numArr = [1, 2, 3];
  2. numArr.forEach((item) => {
  3. item = item * 2;
  4. });
  5. console.log(numArr); // 打印结果:[1, 2, 3]

上面这段代码,你可要看仔细了,打印结果是 [1, 2, 3],不是 [2, 4, 6]

2、数组的元素是引用数据类型:(直接修改整个元素对象时,无法改变原数组)

  1. let objArr = [
  2. { name: 云牧, age: 20 },
  3. { name: 许嵩, age: 30 },
  4. ];
  5. objArr.forEach((item) => {
  6. item = {
  7. name: 邓紫棋,
  8. age: 29,
  9. };
  10. });
  11. console.log(JSON.stringify(objArr));
  12. // 打印结果:[{"name": "云牧","age": 20},{"name": "许嵩","age": 30}]

3、数组的元素是引用数据类型:(修改元素对象里的某个属性时,可以改变原数组)

  1. let objArr = [
  2. { name: 云牧, age: 28 },
  3. { name: 许嵩, age: 30 },
  4. ];
  5. objArr.forEach((item) => {
  6. item.name = 邓紫棋;
  7. });
  8. console.log(JSON.stringify(objArr));
  9. // 打印结果:[{"name":"邓紫棋","age":28},{"name":"邓紫棋","age":30}]

所以其实 forEach 不会直接改变调用它的对象,但是那个对象可能会被 callback 函数改变,上述现象如果了解基础数据类型赋值是值传递,而引用数据类型赋值是引用地址的传递后其实就很好理解啦

我B站也已发布关于基础数据和引用数据类型的区别视频,如不清楚此基础,请务必要补齐哦

如果你需要通过 forEach 修改原数组,建议用 forEach 里面的参数 2 和参数 3 来做,具体请看下面的标准做法

forEach() 通过参数 2、参数 3 修改原数组:(标准做法)

  1. // 1、数组的元素是基本数据类型
  2. let numArr = [1, 2, 3];
  3. numArr.forEach((item, index, arr) => {
  4. arr[index] = arr[index] * 2;
  5. });
  6. console.log(JSON.stringify(numArr)); // 打印结果:[2, 4, 6]
  7. // 2、数组的元素是引用数据类型时,直接修改对象
  8. let objArr = [
  9. { name: 云牧, age: 28 },
  10. { name: 许嵩, age: 34 },
  11. ];
  12. objArr.forEach((item, index, arr) => {
  13. arr[index] = {
  14. name: 小明,
  15. age: 10,
  16. };
  17. });
  18. console.log(JSON.stringify(objArr));
  19. // 打印结果:[{"name":"小明","age":"10"},{"name":"小明","age":"10"}]
  20. // 3、数组的元素是引用数据类型时,修改对象的某个属性
  21. let objArr2 = [
  22. { name: 云牧, age: 28 },
  23. { name: 许嵩, age: 34 },
  24. ];
  25. objArr2.forEach((item, index, arr) => {
  26. arr[index].name = 小明;
  27. });
  28. console.log(JSON.stringify(objArr2));
  29. // 打印结果:[{"name":"小明","age":28},{"name":"小明","age":34}]

总结

如果纯粹只是遍历数组,那么,可以用 forEach() 方法

但是,如果你想在遍历数组的同时,去改变数组里的元素内容,那么,最好是用 map() 方法来做,map() 方法本身会返回一个经过处理后全新的数组,不要用 forEach() 方法,避免出现一些低级错误

sort() 介绍

sort():对数组的元素进行从小到大来排序(会改变原来的数组)

如果在使用 sort() 方法时不带参,

默认排序顺序是在将元素转换为字符串按照Unicode 编码,从小到大进行排序

举例 1:(当数组中的元素为字符串时)

  1. let arr1 = [e, b, d, a, f, c];
  2. let result = arr1.sort(); // 将数组 arr1 进行排序
  3. console.log(arr1 = + JSON.stringify(arr1));
  4. console.log(result = + JSON.stringify(result));

打印结果:

  1. arr1 =["a","b","c","d","e","f"]
  2. result =["a","b","c","d","e","f"]

从上方的打印结果中,我们可以看到,sort 方法会改变原数组,而且方法的返回值也是同样的结果

举例 2:(当数组中的元素为数字时)

  1. let arr2 = [5, 2, 11, 3, 4, 1];
  2. let result = arr2.sort(); // 将数组 arr2 进行排序
  3. console.log(arr2 = + JSON.stringify(arr2));
  4. console.log(result = + JSON.stringify(result));

打印结果:

  1. arr2 = [1,11,2,3,4,5]
  2. result = [1,11,2,3,4,5]

上方的打印结果中,你会发现,使用 sort() 排序后,数字11竟然在数字2的前面。这是为啥呢?因为上面讲到了,sort()方法是按照Unicode 编码进行排序的。

那如果我想让 arr2 里的数字,完全按照从小到大排序,怎么操作呢?继续往下看。

sort()方法:带参时,自定义排序规则

  1. let arr = [5, 2, 11, 3, 4, 1];
  2. arr.sort(function (a, b) {
  3. console.log("a:" + a, "b:" + b);
  4. });
  5. /*
  6. a:2 b:5
  7. a:11 b:2
  8. a:3 b:11
  9. a:4 b:3
  10. a:1 b:4
  11. */

举例:将数组中的数字按照从小到大排序

写法 1:

  1. let arr = [5, 2, 11, 3, 4, 1];
  2. // 自定义排序规则
  3. let result = arr.sort(function (a, b) {
  4. if (a > b) {
  5. // 如果 a 大于 b,则 b 排列 a 之前
  6. return 1;
  7. } else if (a < b) {
  8. // 如果 a 小于 b,,则 a 排列 b 之前
  9. return -1;
  10. } else {
  11. // 如果 a 等于 b,则位置不变
  12. return 0;
  13. }
  14. });
  15. console.log(arr = + JSON.stringify(arr));
  16. console.log(result = + JSON.stringify(result));

打印结果:

  1. arr = [1, 2, 3, 4, 5, 11];
  2. result = [1, 2, 3, 4, 5, 11];

上方代码的写法太啰嗦了,其实也可以简化为如下写法:

写法 2:

  1. let arr = [5, 2, 11, 3, 4, 1];
  2. // 自定义排序规则
  3. let result = arr.sort(function (a, b) {
  4. return a - b; // 升序排列
  5. // return b - a; // 降序排列
  6. });
  7. console.log(arr = + JSON.stringify(arr));
  8. console.log(result = + JSON.stringify(result));

打印结果不变。

上方代码还可以写成 ES6 的形式,也就是将 function 改为箭头函数,其写法如下

写法 3:(箭头函数)

  1. let arr = [5, 2, 11, 3, 4, 1];
  2. // 自定义排序规则
  3. let result = arr.sort((a, b) => {
  4. return a - b; // 升序排列
  5. });
  6. console.log(arr = + JSON.stringify(arr));
  7. console.log(result = + JSON.stringify(result));

上方代码,因为函数体内只有一句话,所以可以去掉 return 语句,继续简化为如下写法

写法 4:(推荐)

  1. let arr = [5, 2, 11, 3, 4, 1];
  2. // 自定义排序规则:升序排列
  3. let result = arr.sort((a, b) => a - b);
  4. console.log(arr = + JSON.stringify(arr));
  5. console.log(result = + JSON.stringify(result));

上面的各种写法中,写法 4 是我们在实战开发中用得最多的。

为了确保代码的简洁优雅,接下来的代码中,凡是涉及到函数,我们将尽量采用 ES6 中的箭头函数来写

sort 方法举例:将数组按里面某个字段从小到大排序

将数组从小到大排序,这个例子很常见。但在实际开发中,总会有一些花样。

下面这段代码,在实际开发中,经常用到,一定要掌握。完整代码如下:

  1. let dataList = [
  2. {
  3. title: "品牌鞋子,高品质低价入手",
  4. publishTime: 200,
  5. },
  6. {
  7. title: "不是很贵,但是很暖",
  8. publishTime: 100,
  9. },
  10. {
  11. title: "无法拒绝的美食,跟我一起吃吃",
  12. publishTime: 300,
  13. },
  14. ];
  15. console.log("排序前的数组:" + JSON.stringify(dataList));
  16. // 将dataList 数组,按照 publishTime 字段,从小到大排序。(会改变原数组)
  17. dataList.sort((a, b) => parseInt(a.publishTime) - parseInt(b.publishTime));
  18. console.log("排序后的数组:" + JSON.stringify(dataList));

打印结果:

  1. 排序前的数组:[
  2. {"title":"品牌鞋子,高品质低价入手","publishTime":200},
  3. {"title":"不是很贵,但是很暖","publishTime":100},
  4. {"title":"无法拒绝的美食,跟我一起吃吃","publishTime":300}
  5. ]
  6. 排序后的数组:[
  7. {"title":"不是很贵,但是很暖","publishTime":100},
  8. {"title":"品牌鞋子,高品质低价入手","publishTime":200},
  9. {"title":"无法拒绝的美食,跟我一起吃吃","publishTime":300}
  10. ]

上方代码中,有人可能会问: publishTime 字段已经是 nuber 类型了,为啥在排序前还要做一次 parseInt() 转换?

这是因为,这种数据一般是后台接口返回给前端的,数据可能是 number 类型、也可能是 string 类型,所以还是统一先做一次 parseInt() 转换数字比较保险。这是一种良好的工作习惯。

其实上面定义时最好优先使用const,能更多保证程序安全,当需要变量时请采用let。

最后悄悄说句像 forEach、map 、filter、some、every、find、findIndex 这些数组原型上的方法除了可以接受第一个回调函数,同时可以接受第二个值用来指定前面回调函数里 this 值(很少用),但是也要注意如果回调函数如果使用箭头函数则无法绑定 this,因为箭头函数没有 this, 始终是取自上层作用域的 this(面试常考,箭头函数也没有 arguments 不过可以使用剩余参数…解决)。


文章标签:

原文连接:https://juejin.cn/post/7087579243638423588

相关推荐

Webpack学习系列 - Webpack5 怎么集成Babel ?

我在淘宝做弹窗,2022 年初的回顾与展望

看完这篇,你也可以搞定有趣的动态曲线绘制

低代码平台的属性面板该如何设计?

34个图片压缩工具集合,包含在线压缩和CLI工具

冴羽答读者问:过程比结果重要吗?如果是,怎么理解?如果不是,又怎么解?

中杯超大杯中间的新选择——vue2.7+vite+ts实践

LiveData源码分析

亚马逊Prime:流媒大战杀手锏

Vue详解知识概括

基于 Docker 来部署 Vue 或 React 前端项目及 Node 后端服务

完美解决自定义字体垂直方向上下偏移的问题

使用vuepress从零开始搭建我的技术文档|已部署到线上

【Vue.js 3.0源码】AST 转换之节点内部转换

小程序+电商,该如何寻找营销增长点

前端如何开始深度学习,那不妨试试JAX

你可能不知道的 前端浏览器(window) 对本地文件操作(File System Access API)

爱奇艺向抖音开启授权,打开内容价值的新大门

使用ComposeDesktop开发一款桌面端多功能APK工具

一个简洁、强大、可扩展的前端项目架构是什么样的?