10分钟了解JS中的常用遍历
2024-11-19 01:11:41

最近写代码频繁写map,以至于想写for…of的时候,都忘记这块的讲究了,索性整理下,以备面试。

正文

常规开发中我们可能已经习惯性的使用map了,但我们肯定不能只会map。

这里我们索性通盘整理下,把前端开发中遍历的熟面孔遍历一遍。

for循环

for循环是一种常用的遍历方法,特别适用于已知遍历次数的情况。

它由三个部分组成:初始化表达式、循环条件和循环迭代器。

这三个表达式用分号分隔。可以使用临时变量将数组的长度缓存起来,避免重复获取数组长度,当数组较大时优化效果会比较明显。

1
2
3
4
const array = [1,2,3,4,5];
for(let i = 0, len = array.length; i < len; i++ ){ //(初始化表达式; 循环条件; 循环迭代器)
console.log(array[i]);
}

for循环非常灵活,你可以根据需要自定义循环变量的初始值、循环条件和迭代方式。它适用于各种遍历需求,包括遍历数组、对象的属性等。

  1. 通过continue中断当次循环
  2. 通过break中断整个循环
  3. 通过retrun中断函数执行

map()

map方法用于对数组的每个元素执行指定的操作,并返回一个新的数组,新数组的元素是原数组经过操作后的结果。

1
2
3
const newArray = array.map((element, index, array) => { // 对每个元素执行操作,并返回新的值
return modifiedElement;
});

map方法中,我们传入一个回调函数作为参数。

该回调函数接受三个参数:当前元素的值element、当前元素的索引index和正在遍历的数组array

在回调函数中,我们对每个元素执行操作,并返回经过操作后的新值modifiedElement

map方法会遍历数组的每个元素,并将每个元素经过回调函数处理后的结果组成一个新的数组。

下面是一个使用map方法的示例:

1
2
3
const newArray = array.map((element) => { // 对每个元素执行操作,并返回新的值
return element * 2;
});

在上述示例中,我们使用map方法对数组array的每个元素进行操作,将每个元素乘以2,并将操作后的结果组成一个新的数组newArray

map方法是一种非常有用的方法,它可以方便地对数组的每个元素进行操作,并生成一个新的数组。

需要注意的是

  • map方法不会修改原始数组,而是返回一个新的数组
  • map方法无法遍历对象,仅适用于数组的遍历
  • map方法不会对空数组进行检测
  • map循环只能通过return中断当次循环

for..in 和 for..of 的区别

for..in

for…in是为遍历对象属性而构建的,它以任意顺序遍历一个对象的除Symbol以外的可枚举属性,可用break或者throw跳出。

1
2
3
4
5
6
7
8
9
let obj = {
name: '张三',
age: 18
}

for(let item in obj) {
console.log(item)
}
// 输出 name age

在JavaScript中,数组也是对象的一种,所以数组也是可以使用for…in遍历

1
2
3
4
5
6
let arr = ['a', 'b', 'c']

for(let item in arr) {
console.log(item)
}
// 输出 0 1 2

for..of

for…of语句在可迭代对象上创建一个迭代循环,调用自定义迭代钩子,并为每个不同属性的值执行语句(包括Array,Map,Set,String,TypedArray,arguments等等,不包括Object),可用break或者throw跳出。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
let arr = ['a', 'b', 'c']

let obj = {
name: '张三',
age: 18,
sex: '男'
}

for (let i of arr) {
console.log(i)
}
// 输出 a b c

for (let i of obj) {
console.log(i)
}
// 报错 obj is not iterable (obj不是可迭代的)

两者区别

无论是for…in还是for…of都是迭代一些东西。它们之间的主要区别在于它们的迭代方式

  • for…in语句以任意顺序迭代对象的可枚举属性
  • for…of语句遍历可迭代对象定义要迭代的数据

总之,for…in 循环主要是为了遍历对象而生,不适用于遍历数组

for…of 循环可以用来遍历数组、类数组对象,字符串、Set、Map 以及 Generator 对象

1
2
3
4
5
6
7
8
9
10
11
12
13
let arr = ['a', 'b', 'c']

Array.prototype.ufo = '张三'

for(let item in arr) {
console.log(item)
}
// 输出 0 1 2 ufo

for(let item of arr) {
console.log(item)
}
// 输出 a b c

使用for….of遍历对象的方法

遍历类数组对象

使用Array.from()方法将对象转换为数组

1
2
3
4
5
6
7
8
9
const obj = {
0:'one',
1:'two',
length: 2
};
obj = Array.from(obj);
for(const k of obj){
console.log(k)
}

遍历普通对象

  • 给对象添加一个[symbol.iterator]属性,并指向一个迭代器。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
const obj = {
a:1,
b:2,
c:3
};

obj[Symbol.iterator] = function(){
const keys = Object.keys(this);
const count = 0;
return {
next(){
if(count<keys.length){
return {value: obj[keys[count++]],done:false};
}else{
return {value:undefined,done:true};
}
}
}
};

for(const k of obj){
onsole.log(k);
}
  • 方法二(使用Generator函数生成迭代器)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
const obj = {
a:1,
b:2,
c:3
};
obj[Symbol.iterator] = function*(){
const keys = Object.keys(obj);
for(const k of keys){
yield [k,obj[k]]
}
};

for(const [k,v] of obj){
console.log(k,v);
}

for 和 forEach区别

  • for循环可以使用break跳出循环,但forEach不能。
  • for循环可以控制循环起点(i初始化的数字决定循环的起点),forEach只能默认从索引0开始。
  • for循环过程中支持修改索引(修改 i),但forEach做不到(底层控制index自增,无法左右它)。

reduce方法

reduce方法用于对数组的每个元素进行累积操作,并返回一个最终的累积结果。

以下是reduce方法的基本语法:

1
2
3
4
// 对每个元素执行累积操作,并返回累积结果
const result = array.reduce(function(accumulator, element, index, array) {
return accumulatedValue;
}, initialValue);

reduce方法中,我们传入一个回调函数作为参数。该回调函数接受四个参数:累积值accumulator、当前元素的值element、当前元素的索引index和正在遍历的数组array

在回调函数中,我们对每个元素执行累积操作,并将累积结果返回。reduce方法会遍历数组的每个元素,并将每个元素经过回调函数处理后的累积结果作为下一次迭代的累积值。

下面是一个使用reduce方法的示例:

1
2
3
4
5
const array = [1, 2, 3, 4, 5];
const result = array.reduce(function(accumulator, element) { // 对每个元素执行累积操作,并返回累积结果
return accumulator + element;
}, 0);
console.log(result); // 输出: 15

在上述示例中,我们使用reduce方法对数组array的每个元素进行累积操作,将所有元素相加得到最终的累积结果。

需要注意的是:

  • reduce方法不会改变原数组。
  • reduce方法可以接受一个可选的初始值initialValue作为第二个参数。如果提供了初始值,累积值accumulator的初始值将为该值;如果未提供初始值,则累积值将为数组的第一个元素,且从数组的第二个元素开始进行累积操作。
  • 如果数组为空,且未提供初始值,则reduce方法会抛出一个TypeError。在处理可能为空的数组时,要确保提供了合适的初始值或进行适当的错误处理。

filter()

filter方法用于筛选数组中满足指定条件的元素,并返回一个新的数组。

以下是filter方法的基本语法:

1
2
3
4
// 返回一个布尔值,表示是否保留该元素
const newArray = array.filter(function(element, index, array) {
return element % 2 === 0; // 保留偶数元素
});

filter方法中,我们传入一个回调函数作为参数。

该回调函数接受三个参数:当前元素的值element、当前元素的索引index和正在遍历的数组array

在回调函数中,我们根据指定的条件判断是否保留该元素。如果回调函数返回true,则该元素将被保留在新的数组中;如果返回false,则该元素将被过滤掉。

下面是一个使用filter方法的示例:

1
2
3
4
5
const array = [1, 2, 3, 4, 5];
const newArray = array.filter(function(element) { // 返回一个布尔值,表示是否保留该元素
return element % 2 === 0; // 保留偶数元素
});
console.log(newArray); // 输出: [2, 4]

在上述示例中,我们使用filter方法筛选数组array中的偶数元素,并将满足条件的元素组成一个新的数组newArray

filter方法非常灵活,可以根据不同的条件筛选数组中的元素。回调函数应该返回一个布尔值,表示是否保留该元素。返回true表示保留,返回false表示过滤掉。

需要注意的是:

  • filter方法会返回一个新的数组,该数组包含满足指定条件的元素。请确保在回调函数中返回一个布尔值,表示是否保留该元素。
  • filter方法不会对空数组进行检测。

some()

some方法用于检测数组中是否至少有一个元素满足指定条件。

以下是some方法的基本语法:

1
2
3
4
// 返回一个布尔值,表示是否满足条件
const result = array.some(function(element) {
return element > 3; // 判断是否存在大于3的元素
});

some方法中,我们传入一个回调函数作为参数。

该回调函数接受三个参数:当前元素的值element、当前元素的索引index和正在遍历的数组array

在回调函数中,我们根据指定的条件判断是否满足条件。如果回调函数返回true,则表示至少有一个元素满足条件;如果所有元素都不满足条件,回调函数返回false

下面是一个使用some方法的示例:

1
2
3
4
5
const array = [1, 2, 3, 4, 5];
const result = array.some(function(element) { // 返回一个布尔值,表示是否满足条件
return element > 3; // 判断是否存在大于3的元素
});
console.log(result); // 输出: true

在上述示例中,我们使用some方法检测数组array中是否存在大于3的元素。

由于数组中存在元素4和5满足条件,所以some方法返回true

some方法可以用于检测数组中是否满足某个条件的元素。它提供了一种简洁的方式来进行条件判断。

需要注意的是:

  • some方法在找到满足条件的元素后会立即停止遍历,不会继续遍历剩余的元素。
  • some方法不会改变原数组,会返回一个布尔值。

every()

every方法用于检测数组中的所有元素是否都满足指定条件。

以下是every方法的基本语法:

1
2
3
4
// 返回一个布尔值,表示是否满足条件
const result = array.every(function(element) {
return element > 0; // 判断是否所有元素都大于0
});

every方法中,我们传入一个回调函数作为参数。

该回调函数接受三个参数:当前元素的值element、当前元素的索引index和正在遍历的数组array

在回调函数中,我们根据指定的条件判断是否满足条件。

如果回调函数对数组中的所有元素都返回true,则every方法返回true;如果有任何一个元素返回false,则every方法返回false

下面是一个使用every方法的示例:

1
2
3
4
5
const array = [1, 2, 3, 4, 5];
const result = array.every(function(element) { // 返回一个布尔值,表示是否满足条件
return element > 0; // 判断是否所有元素都大于0
});
console.log(result); // 输出: true

在上述示例中,我们使用every方法检测数组array中的所有元素是否都大于0。由于数组中的所有元素都大于0,所以every方法返回true

every方法可以用于检测数组中的所有元素是否满足某个条件。它提供了一种简洁的方式来进行条件判断。

需要注意的是:

  • every方法在找到不满足条件的元素后会立即停止遍历,不会继续遍历剩余的元素。
  • every方法不会改变原数组,会返回一个布尔值。

结语

前端遍历循环,最熟悉的陌生人。

平时开发的过程中,很多新人肯定会直接map或者for循环一把梭,这样固然简单有效,但是不够语义化,所以才有了这些api。

我们要尽可能的多用这些原生的API,减少日常开发中不够语义化的问题。

参考

JavaScript | Conistudy

详解JavaScript遍历:掌握for、forEach、for in、for of和map等方法