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]; |