这次盘点的方法主要是用来迭代数组对象的,他们会按照顺序把数组的每个元素传给我们提供的函数,可便于对数组进行迭代,映射,过滤,测试和归并。
在说这些方法之前我们先了解一点所有这些方法都接受一个函数作为他的第一个参数,并且对数组的每个元素(或某些元素)都调用一次这个函数。如果数组是稀疏的,则不会对不存在的数组元素调用传入的这个函数,多数情况下我们提供的这个函数被调用时都会接受到3个参数,分别是数组元素的值,数组元素的索引,和数组元素本身。大多数情况下我们只需要第一个参数,第二和第三我们可以忽略。接下来的方法大多数都要接受可选的第二个参数,如果指定这个参数,这第一个函数在被调用时就好像他是第二个参数的方法一样,换句话说,我们传入的第二个参数会成为作为第一个参数传入的函数内部的this值,传入函数的返回值通常不重要,但不同的方法会议不同的方式处理这个返回值,这次介绍的方法都不会修改调用他们的数组(但是,传入的函数可能会修改这个数组)
1.forEach()
forEach() 方法迭代数组的每一个元素,并对数组的每一个元素都会执行我们指定的函数,传统的forEach()方法传入的第一个参数是一个函数,forEach()在调用这个函数时会给它传3个参数,数组元素的值,数组的索引值,以及数组本身,如果我们只需要操作数组元素的值,只需要传一个参数即可。示例代码如下:
<script>
let data = [1, 2, 3, 4, 5];
// 使用字面量的形式定义一个索引数组
let sum = 0;
// 初始化一个变量用来保存他们相加的和
data.forEach((value) => {
// 调用数组的forEach()方法此时使用的是箭头函数小括号中的value就是数组中的每个值
sum += value;
// 运算他们相加之后的和
});
console.log(sum);
// 控制台输出结果发现为15
</script>
<script>
let data = [1, 2, 3, 4, 5];
// 使用字面量的形式定义一个索引数组
data.forEach(function (v, i, a) {
// 使用forEach()进行循环里面的参数分别是v代表的是数组中的每个参数 i代表的是下标 a代表数组本身
a[i] = v + 1; // 这里也可以写++v
// 将数组的每个元素都+1 然后在返还给原数组
});
console.log(data);
// 输出结果显示数组的每个元素都+1
</script>
我们需要注意的是:forEach()并未提供一种提前总之迭代的方式,换句话说,在这里没有与常规for循环一样的break语句对等的机制
2.map()方法把调用它的数组的每个元素分别传给我们指定的函数,返回这个函数的返回值构成的数组,示例如下:
<script>
let a = [1, 2, 3];
let b = a.map((x) => x * x);
// 我们需要一个变量来接受map函数处理之后的返回值 返回值是一个数组
console.log(b);
// 输出这个数组可以看见 数组的每一个元素都进行了等称操作
</script>
传给map()的函数与传给forEach()的函数会以同样的方式被调用。但对于map()方法来说,我们传入的函数应该返回值,注意,map()返回一个新数组,并不修改调用它的数组。如果数组是稀疏的,则缺失元素不会调用我们的函数,但返回的数组也会与原始数组一样稀疏,长度相同,缺失的元素也相同。
3.filter() 方法返回一个数组,该数组包含调用它的数组的子数组,传给这个方法的函数应该是个断言函数,即返回true或者false的函数。这个函数宇与传给forEach()和map()的函数一样被调用,如果函数返回true或返回值转换为true,则传给这个函数的元素就是filter()最终返回的子数组的成员示例如下:
<script>
let a = [5, 4, 3, 2, 1];
let b = a.filter((x) => x < 3);
// 这里的表达式书写的是条件 如果为true就会生成新的数组保存在变量b中
let c = a.filter((x, i) => i % 2 === 0);
// 这里的表达式书写的是条件 如果为true就会生成新的数组保存在变量b中
console.log(a);
console.log(b);
console.log(c);
</script>
我们需要注意的是:filter()会跳过稀疏数组中缺失的元素,它返回的数组始终是稠密的,因此可以使用一下的方法来清除稀疏数组中的空缺,使之变为稠密数组。示例如下:
<script>
let a = [1, , , null, , 2, 3, 4, 5];
let b = a.filter((a) => true);
console.log(b);
// 此时的条件就是如果有值的情况下就会添加至新的数组如果没有值 就会跳过它
// 如果既想清理空隙,又想删除值为undefined和null的元素,则可以这样子写
let c = a.filter((x) => x !== undefined && x !== null);
console.log(c);
</script>
4.find()与findIndex()方法与filter()类似,表现在他们都是过滤数组,寻找断言函数返回正值的元素,但与filter()不同的是,这两个方法会在断言函数找到第一个元素时停止迭代,此时,find()返回匹配的元素,findIndex()返回匹配元素的索引,如果没有找到匹配的元素,则find()返回undefined,而findIndex()返回-1示例如下:
<script>
let a = [1, 2, 3, 4, 5];
console.log(a.findIndex((x) => x === 3));
// 寻找索引值为3的元素
console.log(a.findIndex((x) => x < 0));
// 寻找索引值小于0的元素值 索引值从0开始所以返回的是-1
console.log(a.findIndex((x) => x % 5 === 0));
// 寻找能够取余5为0的数值的索引值 只有以为是5 索引值为4
console.log(a.findIndex((x) => x % 7 === 0));
// 寻找能够取余7为0的数值的索引值
</script>
5.every()和some()方法是数组断言方法,即他们会对数组元素调用我们传入的断言函数,最后返回true或false
some()方法与数学上的“全程”量词从∨类似,它在且只在断言函数对数组的所有元素都返回true时才返回true示例如下:
<script>
let a = [1, 2, 3, 4, 5];
console.log(a.every((x) => x < 10));
console.log(a.every((x) => x % 2 === 0));
// every()和filter()的最大的区别就是 在filter()中如果满足指定函数中的条件他会生成一个新的数组
// 在every()中必须所有的值都满足指定函数的条件才会返回true 否则就会返回false
</script>
some()函数的用法示例如下:
<script>
/**
* some()方法类似与数组上的"存在"量词ʒ,只要数组元素中有一个让断言函数返回true他就返回true,但必须数组的所有元素对断言函数都返回false它才会
* 返回false
*/
let b = [1, 2, 3, 4, 5];
let r = b.some((x) => x % 2 === 0);
console.log(r);
// true b这个数组中包含偶数
console.log(b.some(isNaN));
// falseb这个数组中并没有不是number的值
</script>
注意:every()和some()都会在他们知道要返回什么值时停止迭代数组,some()在断言函数第一次返回true时返回true,只有全部断言都返回false时才会遍历数组。every()正好相反,他在断言函数第一次返回false的时候返回false,只有在全部断言函数返回true的时候才会遍历数组,同时也要注意,如果在空数组上面调用他们,按照数学的传统,every()返回true,some()返回false.
6.reduce()与reduceRight()
reduce()与reduceRight()方法使用我们指定的函数归并数组元素,最终产生一个值,在函数编程中归并是一个常见操作,有时候也称之为注入(inject)或者折叠(fold)。示例如下配合理解:
<script>
let a = [1, 2, 3, 4, 5];
console.log(a.reduce((x, y) => x + y, 0));
// 所有值的和
console.log(a.reduce((x, y) => x * y, 1));
// 所有值的积
console.log(a.reduce((x, y) => (x > y ? x : y)));
// 求一个最大值
</script>
redcue()接受两个参数,第一个参数是执行归并操作的函数,这个归并函数的任务就是把两个值归并或组合为一个值并返回这个值,在上面的例子中,归并函数通过把两个值相加,相乘和选择最大值来合并两个值,第二个参数是可选的,是传给归并函数的初始值。