JavaScript中数组和对象均可进行遍历。前端开发时,常会用到对数组、对象以及对象数组进行遍历。
1 普通for
循环
与其他语言一致。
1 | let array = [1, 2, 3, 4, 5]; |
可以使用变量缓存数组长度,进行优化。
1 | let array = [1, 2, 3, 4, 5]; |
2 for-in
循环
对于数组,
for-in
循环遍历的是数组的索引值,例如:1
2
3
4let array = [1, 3, 7];
for (const index in array) {
console.log(index); // 0 1 2
}需要注意:这里的索引为字符串,而非数值,不能用于计算;且
for-in
会遍历数组所有可枚举属性(包括原型),因此尽量避免使用for-in
遍历数组。1
2
3
4let array = [1, 3, 7];
for (const index in array) {
console.log(typeof index); // string string string
}对于对象,
for-in
循环遍历的是对象的键名,例如:1
2
3
4
5
6
7let obj = {
id: 1,
name: 'Carlo'
};
for (const key in obj) {
console.log(key); // id name
}需要注意:
for-in
也会遍历到对象原型链上的方法与属性,可以通过hasOwnPropery
方法判断属性是否为实例属性。1
2
3
4
5
6
7
8
9
10Object.prototype.school = 'ZJU'; // 原型属性
let obj = {
id: 1,
name: 'Carlo'
};
for (const key in obj) {
if (obj.hasOwnProperty(key)) {
console.log(key); // id name 不会输出school
}
}
3 for-of
循环
对于数组,
for-of
循环遍历的是数组的元素值,例如:1
2
3
4let array = [1, 3, 7];
for (const item of array) {
console.log(item); // 1 3 7
}for-of
循环不会遍历数组的原型方法与属性,因此是最常用来遍历数组的方法。for-of
循环不支持遍历普通对象,但可以遍历类数组对象、Map和Set等。
以上循环均可以使用break
、continue
、return
语句,例如:
1 | let array = [1, 3, 7]; |
4 对象该怎么遍历?
除上文提到的方法外,对象还可以通过以下方式遍历:
键名用
for-in
获取,键值用obj[key]
获取,会遍历到原型方法与属性。1
2
3
4
5
6
7let obj = {
id: 1,
name: 'Carlo'
};
for (const key in obj) {
console.log(key + ': ' + obj[key]); // id: 1 name: Carlo
}注意:上面第6行取值时不能写
obj.key
,这时key
会被认为是obj
的一个属性,而非循环变量中的key
;也就是obj.key
等同于obj['key']
。使用内建的
Object.keys
方法,会获得由对象实例属性组成的数组,不包含原型方法与属性。1
2
3
4
5
6
7let obj = {
id: 1,
name: 'Carlo'
};
for (const key of Object.keys(obj)) {
console.log(key + ': ' + obj[key]); // id: 1 name: Carlo
}或使用下文提到的
forEach
函数:1
2
3
4
5let obj = {
id: 1,
name: 'Carlo'
};
Object.keys(obj).forEach(key => console.log(key + ': ' + obj[key])); // id: 1 name: Carlo使用内建的
Object.values
方法,会获得由对象实例属性值组成的数组,不包含原型方法与属性;使用内建的Object.entries
方法,会获得由对象实例属性和属性值组成的数组,不包含原型方法与属性。这两个方法与Object.keys
类似,在此不表。类数组对象、字符串、Map、Set等可迭代对象拥有迭代器,可以使用
for-of
遍历。1
2
3
4let string = 'hello'
for (let s of string) {
console.log(s); // h e l l o
}普通对象也可为其添加
Symbol.iterator
方法,并赋一个生成器函数,以使用for-of
遍历:1
2
3
4
5
6
7
8
9
10
11
12let obj = {
id: 1,
name: 'Carlo',
[Symbol.iterator]: function* () {
for (const key of Object.keys(this)) {
yield this[key];
}
}
};
for (const value of obj) {
console.log(value); // 1 Carlo
}
5 数组的高阶遍历函数
下文提到的遍历函数均用于数组,在开发中经常使用。
5.1 forEach
函数
对数组进行遍历,参数为一个匿名回调函数,匿名函数的参数为元素值与索引值(可省略),并且此处索引值为数字格式。
1 | let array = [1, 3, 7]; |
匿名回调函数可以写成箭头函数,更为精简,下文均使用箭头函数。
1 | let array = [1, 3, 7]; |
forEach
功能较弱,甚至不如普通for
循环;并且不能使用break
、continue
、return
语句,类似地,其他高阶函数也不能使用(return
除外)。
5.2 map
函数
map
是映射的意思,它对原数组的每个元素都遍历一次,同时返回一个新的值,并放到新数组中,因此其支持return
,但不能用return
跳出map
,下同。
例如,我们想把一个数组变成其两倍,可通过map
实现:
1 | let array = [1, 3, 7]; |
再例如,对一个对象数组people
,我们想得到所有人的id
数组,即[1, 2, 3]
。
1 | let people = [ |
如果使用forEach
函数,做法如下:
1 | let peopleId = []; |
会发现不得不先创造一个新数组。如果使用map
则精简很多,因为其本身就会返回一个数组:
1 | let peopleId = people.map(person => person.id); |
map
也常被用在构建二维数组中,如:
1 | const dp = new Array(m).fill(0).map(() => new Array(n).fill(0)); |
5.3 filter
函数
filter
是过滤的意思,它对原数组的每个元素都遍历一次,同时返回判断结果(布尔值),将为true
的元素放到新数组中。
例如,我们想把一个数组中的奇数提取出来,可通过filter
实现:
1 | let array = [1, 2, 3, 5, 6, 8]; |
再例如,对对象数组people
,我们想把名字中第二个字母为a的人提取出来,可通过filter
实现:
1 | let people = [ |
5.4 find
函数
find
是寻找的意思,它对原数组的每个元素都遍历一次,同时返回判断结果(布尔值),将第一个为true
的元素返回。
例如,对对象数组people
,我们想把id
为1的人提取出来,通过filter
也可实现:
1 | let people = [ |
如果通过for
循环则是如下逻辑:
1 | let people = [ |
会发现for-if-break
是个连续的逻辑,否则会重复遍历。
如果使用find
则精简很多,因为其本身就会返回所需的元素:
1 | let people = [ |
注意:当filter
找不到任何匹配项时,返回空数组;当find
找不到任何匹配项时,返回undefined
。
5.5 reduce
函数
reduce
可以理解为缩减,它把一个数组逐一缩减为一个值,可通过下面的例子理解。
对下面的对象数组people
,现在想知道每个人的分数总和,通过for
循环是这样实现的:
1 | let people = [ |
reduce
函数传入两个参数,一个是回调函数(参数为初始变量与数组元素),另一个是初始变量的值,即:
1 | let people = [ |
逻辑是:先把0赋给sum
,再对people
里的每个person
做遍历,执行回调函数,并将每一步的返回值赋给sum
。
除累加外,我们还可以使用它进行大小比较。例如,我们想返回分数最高的人,可以这样实现:
1 | let people = [ |
如果reduce
没有给出初始变量的值,数组第一个变量会被赋给初始变量,同时从数组第二个元素开始遍历,注意以下代码的输出结果:
1 | let arr = [1, 3, 7, 10]; |
5.6 结合使用
以上函数可以通过链式编程的思想结合使用。
例如,对一个数组中小于100的数,将其扩大一倍再求和,可以这样实现:
1 | let array = [99, 123, 85, 3, 212, 56]; |