数组的操作-迭代方法

前言

JavaScript数组的迭代方法,前端开发人员想必都不陌生了,在开发中基本上都会用上其中的一种或是几种,说起迭代方法,可能很多人首先想到的就是for循环,我之前遍历数组的时候用的最多的就是for,但是在开始使用的迭代方法之后,就很少使用for循环进行数组操作了,我最常用的是 map和foreach ,也会使用every和some,如果使用得当,不仅可以减少代码冗余,提升可读性和可维护性,也可以在一定程度上优化性能。

es5新增了几个数组的迭代方法(every,filter,forEach,map,some),好了,废话不多说,下面开始进入到我们的正题,介绍各个方法的使用情况。
参数:这些方法都接收两个参数callback是数组每一项执行的那个指定函数,使用三个参数,thisArg(可选,执行 callback 函数时 使用的this 值)callback参数如下

  • currentValue,第一个参数,数组中正在处理的当前元素
  • index,第二个参数,数组中正在处理的当前元素的索引 (可选)
  • array,方法被调用的数组(可选)

1.map方法

为数组每一项执行一个指定函数,返回每次函数调用的结果组成的数组。这个是我使用的最多的,eg: 在react中循环输出组件

??? 试想一下,现在有一个需求,给定一个数组,然后给数组里面的每一项加1

我们先来看下for循环是怎么实现的

1
2
3
4
let array = [3, 6, 12, 33, 52]  
for(let i = 0; i < array.length; i++) {
array[i] += 1
}

map方法实现

1
array = array.map(function(item) {return item + 1})

map的es6写法

1
array = array.map(item => item + 1)

2.forEach方法

forEach()对数组中的每一项运行给定函数 ;简单点来说,本质上跟for没有区别,只是写法不一样。 它的使用也和map类似,参数也类似,只是这个方法没有返回值。这个方法比较简单,只说一些注意的点吧:

  • forEach和map一样,如果数组在迭代时被修改了,则其他元素会被跳过,看下面一个例子
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    let words = ["one", "two", "three", "four"];
    words.forEach((word) => {
    console.log(word);
    if (word === "two") {
    words.shift();
    }
    });
    // one
    // two
    // four

当word=“two”时,删掉数组的第一个元素,那么数组的每一项都会往前移动一个位置,因为元素 “four”现在在数组更前的位置,”three”会被跳过。 forEach()不会在迭代之前创建数组的副本。

  • forEach没有办法中止或者跳出循环,除非抛出一个异常。

3.filter方法

filter():对数组中的每一项运行给定函数。该函数会返回true的项组成的数组。

筛选出分数大于60分的同学。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
let stu = [
{
name: 'mabiao',
score: 43,
flower: 3
},
{
name: 'haohua',
score: 87,
flower: 2
},
{
name: 'dahuang',
score: 74,
flower: 4
},
]
let qua_stu = stu.filter(item => item.score >= 60)
console.log(qua_stu)

还有一个应用是数组去重,用filter也是比较容易实现的。eg:
先来看看for循环是怎么实现的

1
2
3
4
5
6
7
var newarr = [],
arr = ['hello', 'hi', 'world', 'hello', 'apple', 'world', 'dream']
for(var i = 0,len = arr.length;i < len; i++){
if(newarr.indexOf(arr[i])===-1){
newarr.push(arr[i]);
}
}

再来对比一下filter,是不是精简了很多。

1
2
3
newarr = arr.filter((item,index,self) => {
return self.indexOf(item) == index
})

4.Every和Some

因为这两个方法的使用场景很像,所以就一起写了。
every()对数组中的每一项运行给定函数,如果该函数对每一项都返回true,则返回true;
some()对数组中的每一项运行给定函数,如果该函数对任一项返回true,则返回true;
every相当于并且,some相当于或

检测数组中的所有元素是否都大于 10
1
2
3
let arr = [12, 5, 8, 13, 44]
var passed = arr.every((item) => item > 10)
console.log(passed) // false
检测在数组中是否有元素大于 10
1
2
passed = arr.some((item) => item > 10)
console.log(passed) //true

补充 (es6新增的数组迭代方法)

1.for-of

介绍for of之前,先来看看什么是Iterator(遍历器)以下摘至es6标准入门的Iterator,只有一部分定义,要了解更多的可以去看看可以去看阮大神的es6标准入门
  • JavaScript 原有的表示“集合”的数据结构,主要是数组(Array)和对象(Object),ES6 又添加了Map和Set。这样就有了四种数据集合,用户还可以组合使用它们,定义自己的数据结构,比如数组的成员是Map,Map的成员是对象。这样就需要一种统一的接口机制,来处理所有不同的数据结构。
  • 遍历器(Iterator)就是这样一种机制。它是一种接口,为各种不同的数据结构提供统一的访问机制。任何数据结构只要部署 Iterator 接口,就可以完成遍历操作(即依次处理该数据结构的所有成员)。
  • Iterator 的作用有三个:一是为各种数据结构,提供一个统一的、简便的访问接口;二是使得数据结构的成员能够按某种次序排列;三是 ES6 创造了一种新的遍历命令for…of循环,Iterator 接口主要供for…of消费。
  • 那么问题来了,一个数据结构只要部署了Symbol.iterator属性,就被视为具有 iterator 接口,就可以用for…of循环遍历它的成员。也就是说,for…of循环内部调用的是数据结构的Symbol.iterator方法。
  • for…of循环可以使用的范围包括数组、Set 和 Map 结构、某些类似数组的对象(比如arguments对象、DOM NodeList 对象)、Generator 对象,以及字符串。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    const arr = ['red', 'green', 'blue'];

    for(let v of arr) {
    console.log(v); // red green blue
    }

    const obj = {};
    obj[Symbol.iterator] = arr[Symbol.iterator].bind(arr);

    for(let v of obj) {
    console.log(v); // red green blue
    }

空对象obj部署了数组arr的Symbol.iterator属性,结果obj的for…of循环,产生了与arr完全一样的结果。

for in 循环是获得键值,for of 允许遍历获得值

1
2
3
4
5
6
7
8
9
var arr = ['a', 'b', 'c', 'd'];

for (let a in arr) {
console.log(a); // 0 1 2 3
}

for (let a of arr) {
console.log(a); // a b c d
}

for…of循环调用遍历器接口,数组的遍历器接口只返回具有数字索引的属性。

1
2
3
4
5
6
let arr = [3, 5, 7];
arr.foo = 'hello';

for (let i of arr) {
console.log(i); // "3", "5", "7"
}

好了,先介绍到这里,这里只是简单描述了数组迭代方法的使用,具体项目中的使用还需要大家亲自操刀实践,实践才能出真知,谢谢!!!
感谢支持,我会不断进步