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

更新日期: 2022-05-12阅读量: 163标签: 数组

forEach() 介绍

forEach()方法需要一个回调函数(这种函数,是由我们创建但是不由我们调用的)作为参数

回调函数中传递三个参数:

  • 第一个参数,就是当前正在遍历的元素
  • 第二个参数,就是当前正在遍历的元素的索引
  • 第三个参数,就是正在遍历的数组

代码举例:

let myArr = ['王一', '王二', '王三'];

myArr.forEach((item, index, arr) => {
    console.log('item:' + item);
    console.log('index:' + index);
    console.log('arr:' + JSON.stringify(arr));
});

打印结果:

item:王一
index:0
arr:["王一","王二","王三"]
----------
item:王二
index:1
arr:["王一","王二","王三"]
----------
item:王三
index:2
arr:["王一","王二","王三"]
----------

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

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

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

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

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

let numArr = [1, 2, 3];

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

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

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

let objArr = [
    { name: '云牧', age: 20 },
    { name: '许嵩', age: 30 },
];

objArr.forEach((item) => {
    item = {
        name: '邓紫棋',
        age: '29',
    };
});
console.log(JSON.stringify(objArr)); 
// 打印结果:[{"name": "云牧","age": 20},{"name": "许嵩","age": 30}]

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

let objArr = [
    { name: '云牧', age: 28 },
    { name: '许嵩', age: 30 },
];

objArr.forEach((item) => {
    item.name = '邓紫棋';
});
console.log(JSON.stringify(objArr));
// 打印结果:[{"name":"邓紫棋","age":28},{"name":"邓紫棋","age":30}]

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

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

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

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

// 1、数组的元素是基本数据类型
let numArr = [1, 2, 3];

numArr.forEach((item, index, arr) => {
    arr[index] = arr[index] * 2;
});
console.log(JSON.stringify(numArr)); // 打印结果:[2, 4, 6]

// 2、数组的元素是引用数据类型时,直接修改对象
let objArr = [
    { name: '云牧', age: 28 },
    { name: '许嵩', age: 34 },
];

objArr.forEach((item, index, arr) => {
    arr[index] = {
        name: '小明',
        age: '10',
    };
});
console.log(JSON.stringify(objArr)); 
// 打印结果:[{"name":"小明","age":"10"},{"name":"小明","age":"10"}]

// 3、数组的元素是引用数据类型时,修改对象的某个属性
let objArr2 = [
    { name: '云牧', age: 28 },
    { name: '许嵩', age: 34 },
];

objArr2.forEach((item, index, arr) => {
    arr[index].name = '小明';
});
console.log(JSON.stringify(objArr2)); 
// 打印结果:[{"name":"小明","age":28},{"name":"小明","age":34}]

总结

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

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

sort() 介绍

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

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

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

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

let arr1 = ['e', 'b', 'd', 'a', 'f', 'c'];

let result = arr1.sort(); // 将数组 arr1 进行排序

console.log('arr1 =' + JSON.stringify(arr1));
console.log('result =' + JSON.stringify(result));

打印结果:

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

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

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

let arr2 = [5, 2, 11, 3, 4, 1];

let result = arr2.sort(); // 将数组 arr2 进行排序

console.log('arr2 =' + JSON.stringify(arr2));
console.log('result =' + JSON.stringify(result));

打印结果:

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

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

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

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

如果在 sort()方法中带参,我们就可以自定义排序规则。具体做法如下:

我们可以在 sort()添加一个回调函数,来指定排序规则。

回调函数中需要定义两个形参,浏览器将会分别使用数组中的元素作为实参去调用回调函数。

浏览器根据回调函数的返回值来决定元素的排序:(重要)

  • 如果 compareFunction(a, b) 小于 0 ,那么 a 会被排列到 b 之前;
  • 如果 compareFunction(a, b) 等于 0 , a 和 b 的相对位置不变
  • 如果 compareFunction(a, b) 大于 0 , b 会被排列到 a 之前

如果只是看上面的文字,可能不太好理解,我们来看看下面的例子,你肯定就能明白

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

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

写法 1:

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

// 自定义排序规则
let result = arr.sort(function (a, b) {
    if (a > b) {
        // 如果 a 大于 b,则 b 排列 a 之前
        return 1;
    } else if (a < b) {
        // 如果 a 小于 b,,则 a 排列 b 之前
        return -1;
    } else {
        // 如果 a 等于 b,则位置不变
        return 0;
    }
});

console.log('arr =' + JSON.stringify(arr));
console.log('result =' + JSON.stringify(result));

打印结果:

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

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

写法 2:

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

// 自定义排序规则
let result = arr.sort(function (a, b) {
    return a - b; // 升序排列
    // return b - a; // 降序排列
});

console.log('arr =' + JSON.stringify(arr));
console.log('result =' + JSON.stringify(result));

打印结果不变。

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

写法 3:(箭头函数)

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

// 自定义排序规则
let result = arr.sort((a, b) => {
    return a - b; // 升序排列
});

console.log('arr =' + JSON.stringify(arr));
console.log('result =' + JSON.stringify(result));

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

写法 4:(推荐)

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

// 自定义排序规则:升序排列
let result = arr.sort((a, b) => a - b);

console.log('arr =' + JSON.stringify(arr));
console.log('result =' + JSON.stringify(result));

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

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

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

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

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

let dataList = [
        {
          title: "品牌鞋子,高品质低价入手",
          publishTime: 200,
        },
        {
          title: "不是很贵,但是很暖",
          publishTime: 100,
        },
        {
          title: "无法拒绝的美食,跟我一起吃吃",
          publishTime: 300,
        },
      ];

 console.log("排序前的数组:" + JSON.stringify(dataList));

 // 将dataList 数组,按照 publishTime 字段,从小到大排序。(会改变原数组)
 dataList.sort((a, b) => parseInt(a.publishTime) - parseInt(b.publishTime));

 console.log("排序后的数组:" + JSON.stringify(dataList));

打印结果:

排序前的数组:[
    {"title":"品牌鞋子,高品质低价入手","publishTime":200},
    {"title":"不是很贵,但是很暖","publishTime":100},
    {"title":"无法拒绝的美食,跟我一起吃吃","publishTime":300}
]

排序后的数组:[
    {"title":"不是很贵,但是很暖","publishTime":100},
    {"title":"品牌鞋子,高品质低价入手","publishTime":200},
    {"title":"无法拒绝的美食,跟我一起吃吃","publishTime":300}
]

上方代码中,有人可能会问: 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

链接: https://www.fly63.com/article/detial/11494

探索JavaScript数组奥秘

avaScript数组同后端语言一样,具有它自己的数据结构,归根结底,这种数据结构,本质就是一种集合。在后端语言中(如java,.net等),数组是这样定义的:数组是用来存储相同数据类型的集合

js使用数组+循环+条件实现数字转换为汉字的简单方法。

单个数字转汉字的解决方法:利用数组存储0-9的汉字、 ary.length和str.length不用多说,这是指ary数组和str字符串的长度。这里我们需要注意的是str.charAt(j)和ary[i],分别指在str这个字符串中索引为j的元素,在ary中索引为i的元素。

[译]async-await 数组循环的几个坑

在 Javascript 循环中使用 async/ await 循环遍历数组似乎很简单,但是在将两者结合使用时需要注意一些非直观的行为。让我们看看三个不同的例子,看看你应该注意什么,以及哪个循环最适合特定用例。

数组、字符串去重

今天说的数组和字符串去重呢,主要用到es6新的数据结构 Set,它类似于数组,但是成员的值都是唯一的,没有重复的值,所以活用Set来进行数组和字符串的去重。

JavaScript 数组方法

数组方法:1、Array.join([param]) 方法:将数组中所有的元素都转换为字符串并连接起来,通过字符 param 连接,默认使用逗号,返回最后生成的字符串2、Array.reverse() 方法:将数组中的元素颠倒顺序(在原数组中重新排列它们),返回逆序数组

如何删除JavaScript 数组中的虚值

falsy(虚值)是在 Boolean 上下文中已认定可转换为‘假‘的值.JavaScript 在需要用到布尔类型值的上下文中使用强制类型转换(Type Conversion )将值转换为布尔值,比如:在条件语句或者循环语句中。

JavaScript中十种一步拷贝数组的方法

JavaScript中我们经常会遇到拷贝数组的场景,但是都有哪些方式能够来实现呢,我们不妨来梳理一下。扩展运算符(浅拷贝)自从ES6出现以来,这已经成为最流行的方法。

JS数组的几个经典api

本文主要来讲数组api的一些操作,如简单实现扁平化n维数组、数组去重、求数组最大值、数组求和、排序、对象和数组的转化等。扁平化嵌套数组/展平和阵列孔——flat()

关于Vue不能监听(watch)数组变化

vue无法监听数组变化的情况,但是数组在下面两种情况下无法监听:利用索引直接设置数组项时,例如arr[indexofitem]=newValue;修改数组的长度时,例如arr.length=newLength

JS计算两个数组的交集、差集、并集、补集(多种实现方式)

使用 ES5 语法来实现虽然会麻烦些,但兼容性最好,不用考虑浏览器 JavaScript 版本,使用 ES5 语法来实现虽然会麻烦些,但兼容性最好,不用考虑浏览器 JavaScript 版本。也不用引入其他第三方库。

点击更多...

内容以共享、参考、研究为目的,不存在任何商业目的。其版权属原作者所有,如有侵权或违规,请与小编联系!情况属实本人将予以删除!