0%

数组的遍历

列出所有的数组遍历方法,方便查阅。

for ( ; ; ) { … }

这是最传统的方法

1
2
3
4
5
6
7
8
const arr=[1,2,3];
for(let i=0;i<arr.length;i++){
console.log(arr[i]);
}
// 输出
1
2
3

for … in

语法如下:

1
2
for(variable in object)
statement

variable 是声明一个变量的语句,在循环体内部,对象的一个属性名会被作为字符串赋给变量 variable。数组也是一种特殊的 Object。

该方法不仅可以遍历数组,还可以遍历对象。对象的有些属性标记成了只读的,永久的(不可删除的)或者不可枚举的,这些属性使用 for/in 循环不能枚举出来。虽然所有的用户定义的属性都可以枚举,但是许多内部属性,包括所有的内部方法都是不可枚举的。另外对象可以继承其他对象的属性,那些已继承的用户定义的属性可以使用 for/in 循环枚举出来。

1
2
3
4
5
6
7
8
const arr=[1,2,3];
for(let i in arr){
console.log(arr[i]);
}
// 输出
1
2
3

for ... in 方法只能遍历出对象可枚举的属性,判断对象的属性是否是可枚举的可以使用 Object.propertyIsEnumerable() 来判断。该方法返回一个布尔值,表明指定的属性名是否是当前对象可枚举的自身属性。

1
2
const obj = {prop: 123};
obj.propertyIsEnumerable('prop') // true

要修改一个对象属性的可枚举等属性需要用到 Object.defineProperty(obj, prop, descriptor) 方法。

for … of

遍历 Array 可以采用下标循环,遍历 Map 和 Set 就无法使用下标。Map,Set结构无下标,无法使用索引进行遍历。为了统一集合类型,ES6 标准引入了新的 iterable 类型。

ArrayMapSet都属于 iterable 类型。具有 iterable 类型的集合可以通过新的for … of循环来遍历。

1
2
3
4
5
6
7
8
const arr=[1,2,3];
for(let i of arr){
console.log(i);
}
// 输出
1
2
3

for … of 循环和 for … in 循环有何区别

for … in循环,它遍历的实际上是对象的属性名称。一个 Array 数组实际上也是一个对象,它的每个元素的索引被视为一个属性。当我们手动给 Array 对象添加了额外的属性后,for … in循环将带来意想不到的意外效果:

1
2
3
4
5
6
7
8
9
const arr=[1,2,];
arr.len = 3;
for(let i in arr){
console.log(i + ' ' + arr[i]);
}
// 输出
0 1
1 2
len 3

而当我们使用 for ... of 时,它实际上是遍历的数组的值:

1
2
3
4
5
6
7
8
const arr=[1,2,];
arr.len = 3;
for(let i of arr){
console.log(i);
}
// 输出
1
2

forEach

该方法是 ES5.1 标准引入的。方法返回值为 undefined 并且不可链式调用,没有办法中止或者跳出 forEach 循环,除了抛出一个异常。

该方法按升序为数组中含有效值的每一项执行一次 callback 函数,那些已删除(使用 delete 方法等情况)或者未初始化的项将被跳过(但不包括那些值为 undefined 的项)(例如在稀疏数组上)。

forEach 遍历的范围在第一次调用 callback 前就会确定。调用 forEach 后添加到数组中的项不会被 callback访问到。如果已经存在的值被改变,则传递给 callback 的值是 forEach 遍历到他们那一刻的值。已删除的项不会被遍历到。如果已访问的元素在迭代时被删除了(例如使用 shift()) ,之后的元素将被跳过。

使用方法如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
array.forEach(callback(currentValue, index, array){
//do something
}, this)

array.forEach(callback[, thisArg])

callback
为数组中每个元素执行的函数,该函数接收三个参数:
currentValue(当前值)
数组中正在处理的当前元素。
index(索引)
数组中正在处理的当前元素的索引。
array
forEach()方法正在操作的数组。
thisArg(可选)
可选参数。当执行回调函数时用作this的值(参考对象)。

如果给forEach传递了thisArg参数,当调用时,它将被传给 callback 函数,作为它的 this 值。否则,将会传入 undefined 作为它的 this 值。

1
2
3
4
5
6
const arr=[1,2,3];
arr.forEach((v,i) => console.log( i + ' ' + v ))
// 输出
0 1
1 2
2 3

map

该方法返回一个新数组,数组中每个元素都是调用提供的函数后返回的结果,原数组不变

使用方法为(参数含义与 forEach 相似):

1
2
3
let array = arr.map(function callback(currentValue, index, array) {
// Return element for new_array
}[, thisArg])
1
2
3
var numbers = [1, 4, 9];
var roots = numbers.map(Math.sqrt);
// roots的值为[1, 2, 3], numbers的值仍为[1, 4, 9]

该方法后续可以跟上数组其他方法,例如:

1
2
3
var str = '12345';
Array.prototype.map.call(str, x => x).reverse().join('');
// "54321"

reduce

该方法对累加器和数组中的每个元素(从左到右)应用一个函数,将其减少为单个值,并返回这个值。原数组不变

1
arr.reduce(function (previous, current, index, arr) { ... }[, initialValue])

callback 函数接受 4 个参数:之前值、当前值、索引值以及数组本身。initialValue参数可选,表示初始值。若指定,则当作最初使用的previous值;如果缺省,则使用数组的第一个元素作为previous初始值,同时current往后排一位,相比有initialValue值少一次迭代。

1
2
let sum = [1, 2, 3, 4].reduce((previous, current, index, array) => previous + current);
sum // 10

filter

返回经过过滤后的数组。原数组不变,用法与forEach相似。

1
array.filter(callback,[ thisObject]);

filtercallback函数需要返回布尔值truefalse。如果为true,则表示通过筛选;若为false,则会被过滤掉。返回值只需要弱等于== true/false就可以了,并非=== true/false

1
2
3
var data = [0, 1, 2, 3];
data.filter(item => item >= 2);
// [2, 3]

some

该方法测试数组中的某些元素是否通过由提供的函数给出的条件。若某一项符合则返回true,否则返回false原数组不变

1
arr.some(callback[, thisArg])

callback函数需要返回值,只需要弱等于== true/false就可以了。我们自然可以使用forEach进行判断,不过,相比some, 不足在于,some只有有true即返回不再执行了。

1
2
3
var scores = [5, 8, 3, 10];
scores.some(item => item > 8);
// true

every

用法与some完全相似,区别在于every需要所有的元素都满足条件才会返回true,某一项不符合就会返回false