7. 归并方法
ECMAScript为数组提供了两个归并方法:reduce()和reduceRight()。下面就分别来看看这两个方法。
(1)reduce()
reduce() 方法对数组中的每个元素执行一个reducer函数(升序执行),将其结果汇总为单个返回值。其使用语法如下:
arr.reduce(callback,[initialValue])
reduce 为数组中的每一个元素依次执行回调函数,不包括数组中被删除或从未被赋值的元素,接受四个参数:初始值(或者上一次回调函数的返回值),当前元素值,当前索引,调用 reduce 的数组。
(1) callback (执行数组中每个值的函数,包含四个参数)
- previousValue (上一次调用回调返回的值,或者是提供的初始值(initialValue))
- currentValue (数组中当前被处理的元素)
- index (当前元素在数组中的索引)
- array (调用 reduce 的数组)
(2) initialValue (作为第一次调用 callback 的第一个参数。)
let arr = [1, 2, 3, 4]
let sum = arr.reduce((prev, cur, index, arr) => {
console.log(prev, cur, index);
return prev + cur;
})
console.log(arr, sum);
输出结果:
1 2 1
3 3 2
6 4 3
[1, 2, 3, 4] 10
如果添加了初始值:
let arr = [1, 2, 3, 4]
let sum = arr.reduce((prev, cur, index, arr) => {
console.log(prev, cur, index);
return prev + cur;
}, 5)
console.log(arr, sum);
结果:
5 1 0
6 2 1
8 3 2
11 4 3
[1, 2, 3, 4] 15
可以得出结论:如果没有提供initialValue,reduce 会从索引1的地方开始执行 callback 方法,跳过第一个索引。如果提供initialValue,从索引0开始。
注意,该方法如果添加初始值,就会改变原数组,将这个初始值放在数组的最后一位。
(2)reduceRight()
该方法和的上面的reduce()用法几乎一致,只是该方法是对数组进行倒序查找的。而reduce()方法是正序执行的
let arr = [1, 2, 3, 4]
let sum = arr.reduceRight((prev, cur, index, arr) => {
console.log(prev, cur, index);
return prev + cur;
}, 5)
console.log(arr, sum);
结果:
5 4 3
9 3 2
12 2 1
14 1 0
[1, 2, 3, 4] 15
8. 搜索和位置方法
ECMAScript提供了两类搜索数组的方法:按照严格相等搜索和按照断言函数搜索。
(1)三个方法
ECMAScript通过了3个严格相等的搜索方法:indexOf()、lastIndexOf()、includes()。这些方法都接收两个参数:要查找的元素和可选的其实搜索位置。lastIndexOf()方法会从数组结尾元素开始向前搜索,其他两个方法则会从数组开始元素向后进行搜索。indexOf()和lastIndexOf()返回的是查找元素在数组中的索引值,如果没有找到,则返回-1。includes()方法会返回布尔值,表示是否找到至少一个与指定元素匹配的项。
使用示例如下:
let arr = [1, 2, 3, 4, 5];
console.log(arr.indexOf(2)) // 1
console.log(arr.lastIndexOf(3)) // 2
console.log(arr.includes(4)) // true
(2)断言函数
ECMAScript也允许按照定义的断言函数搜索数组,每个索引都会调用这个函数,断言函数的返回值决定了相应索引的元素是否被认为匹配。使用断言函数的方法有两个,分别是find()和findIndex()方法。这两个方法对于空数组,函数是不会执行的。并且没有改变数组的原始值。他们的都有三个参数:元素、索引、元素所属的数组对象,其中元素是数组中当前搜索的元素,索引是当前元素的索引,而数组是当前正在搜索的数组。
这两个方法都从数组的开始进行搜索,find()返回的是第一个匹配的元素,如果没有符合条件的元素返回 undefined;findIndex()返回的是第一个匹配的元素的索引,如果没有符合条件的元素返回 -1。
使用示例如下:
let arr = [1, 2, 3, 4, 5]
arr.find(item => item > 2) // 结果: 3
arr.findIndex(item => item > 2) // 结果: 2
9. 迭代器方法
在ES6中,Array的原型上暴露了3个用于检索数组内容的方法:keys()、values()、entries()。keys()方法返回数组索引的迭代器,values()方法返回数组元素的迭代器,entries()方法返回索引值对的迭代器。
因为这些方法返回的都是迭代器,所以可以将他们的内容通过Array.from直接转化为数组实例:
let array = ["one", "two", "three", "four", "five"];
console.log(Array.from(array.keys())) // [0, 1, 2, 3, 4]
console.log(Array.from(array.values())) // ["one", "two", "three", "four", "five"]
console.log(Array.from(array.entries())) // [[0, "one"], [1, "two"], [2, "three"], [3, "four"], [4, "five"]]
10. 迭代方法
ECMAScript为数组定义了5个迭代方法,分别是every()、filter()、forEach()、map()、some()。这些方法都不会改变原数组。这五个方法都接收两个参数:以每一项为参数运行的函数和可选的作为函数运行上下文的作用域对象(影响函数中的this值)。传给每个方法的函数接收三个参数,分别是当前元素、当前元素的索引值、当前元素所属的数对象。
(1)forEach()
forEach 方法用于调用数组的每个元素,并将元素传递给回调函数。该方法没有返回值,使用示例如下:
let arr = [1,2,3,4,5]
arr.forEach((item, index, arr) => {
console.log(index+":"+item)
})
该方法还可以有第二个参数,用来绑定回调函数内部this变量(回调函数不能是箭头函数,因为箭头函数没有this):
let arr = [1,2,3,4,5]
let arr1 = [9,8,7,6,5]
arr.forEach(function(item, index, arr){
console.log(this[index]) // 9 8 7 6 5
}, arr1)
(2)map()
map() 方法会返回一个新数组,数组中的元素为原始数组元素调用函数处理后的值。该方法按照原始数组元素顺序依次处理元素。该方法不会对空数组进行检测,它会返回一个新数组,不会改变原始数组。使用示例如下:
let arr = [1, 2, 3];
arr.map(item => {
return item+1;
})
// 结果: [2, 3, 4]
第二个参数用来绑定参数函数内部的this变量:
var arr = ['a', 'b', 'c'];
[1, 2].map(function (e) {
return this[e];
}, arr)
// 结果: ['b', 'c']
该方法可以进行链式调用:
let arr = [1, 2, 3];
arr.map(item => item+1).map(item => item+1)
// 结果: [3, 4, 5]
forEach和map 区别如下:
- forEach()方法:会针对每一个元素执行提供的函数,对数据的操作会改变原数组,该方法没有返回值;
- map()方法:不会改变原数组的值,返回一个新数组,新数组中的值为原数组调用函数处理之后的值;
(3)filter()
filter()方法用于过滤数组,满足条件的元素会被返回。它的参数是一个回调函数,所有数组元素依次执行该函数,返回结果为true的元素会被返回。该方法会返回一个新的数组,不会改变原数组。
let arr = [1, 2, 3, 4, 5]
arr.filter(item => item > 2)
// 结果:[3, 4, 5]
可以使用filter()方法来移除数组中的undefined、null、NAN等值
let arr = [1, undefined, 2, null, 3, false, '', 4, 0]
arr.filter(Boolean)
// 结果:[1, 2, 3, 4]
(4)every()
该方法会对数组中的每一项进行遍历,只有所有元素都符合条件时,才返回true,否则就返回false。
let arr = [1, 2, 3, 4, 5]
arr.every(item => item > 0)
// 结果: true
(5)some()
该方法会对数组中的每一项进行遍历,只要有一个元素符合条件,就返回true,否则就返回false。
let arr = [1, 2, 3, 4, 5]
arr.some(item => item > 4)
// 结果: true
11. 其他方法
除了上述方法,遍历数组的方法还有for...in和for...of
(1)for…in
for…in 主要用于对数组或者对象的属性进行循环操作。循环中的代码每执行一次,就会对对象的属性进行一次操作。其使用语法如下:
for (var item in object) {
执行的代码块
}
其中两个参数:
- item:必须。指定的变量可以是数组元素,也可以是对象的属性。
- object:必须。指定迭代的的对象。
使用示例如下
const arr = [1, 2, 3];
for (var i in arr) {
console.log('键名:', i);
console.log('键值:', arr[i]);
}
结果:
键名: 0
键值: 1
键名: 1
键值: 2
键名: 2
键值: 3
需要注意,该方法不仅会遍历当前的对象所有的可枚举属性,还会遍历其原型链上的属性。 除此之外,该方法遍历数组时候,遍历出来的是数组的索引值,遍历对象的时候,遍历出来的是键值名。
(2)for...of
for...of 语句创建一个循环来迭代可迭代的对象。在 ES6 中引入的 for...of 循环,以替代 for...in 和 forEach() ,并支持新的迭代协议。for...of 允许遍历 Arrays(数组), Strings(字符串), Maps(映射), Sets(集合)等可迭代的数据结构等。
for (var item of iterable) {
执行的代码块
}
其中两个参数:
- item:每个迭代的属性值被分配给该变量。
- iterable:一个具有可枚举属性并且可以迭代的对象。
该方法允许获取对象的键值:
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适用遍历 数组/ 类数组/字符串/map/set 等拥有迭代器对象的集合;
- 它可以正确响应break、continue和return语句;
- for...of循环不支持遍历普通对象,因为没有迭代器对象。如果想要遍历一个对象的属性,可以用
for-in循环。
总结,for…of 和for…in的区别如下:
- for…of 遍历获取的是对象的键值,for…in 获取的是对象的键名;
- for… in 会遍历对象的整个原型链,性能非常差不推荐使用,而 for … of 只遍历当前对象不会遍历原型链;
- 对于数组的遍历,for…in 会返回数组中所有可枚举的属性(包括原型链上可枚举的属性),for…of 只返回数组的下标对应的属性值;
(3)flat()
在ES2019中,flat()方法用于创建并返回一个新数组,这个新数组包含与它调用flat()的数组相同的元素,只不过其中任何本身也是数组的元素会被打平填充到返回的数组中:
[1, [2, 3]].flat() // [1, 2, 3]
[1, [2, [3, 4]]].flat() // [1, 2, [3, 4]]
在不传参数时,flat()默认只会打平一级嵌套,如果想要打平更多的层级,就需要传给flat()一个数值参数,这个参数表示要打平的层级数:
[1, [2, [3, 4]]].flat(2) // [1, 2, 3, 4]