1. for
循环
-
基本语法:
-
for
循环是最基本的循环结构,它的语法是for(初始化表达式; 条件表达式; 更新表达式) { 循环体语句 }
。例如,要遍历一个从 0 到 9 的数组:
-
let arr = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
for (let i = 0; i < arr.length; i++) {
console.log(arr[i]);
}
-
特点:
- 它可以精确地控制循环的起始、结束条件和每次迭代的步长。在上述例子中,
i
从 0 开始(初始化表达式),只要i
小于数组的长度(条件表达式),就会执行循环体,并且每次循环后i
会自增 1(更新表达式)。 - 适用于已知循环次数的情况,比如遍历数组或执行固定次数的操作。
- 它可以精确地控制循环的起始、结束条件和每次迭代的步长。在上述例子中,
-
性能方面:
-
for
循环在性能上比较高效,因为它的执行逻辑很简单直接。在大多数浏览器中,它的执行速度相对较快,特别是在处理简单的遍历任务时。
-
2. for...in
循环
-
基本语法:
for...in
语句用于遍历对象的可枚举属性。语法是for (变量 in 对象) { 循环体语句 }
。例如,遍历一个包含一些属性的对象:
let person = {
name: 'John',
age: 30,
city: 'New York'
};
for (let key in person) {
console.log(key + ': ' + person[key]);
}
-
特点:
- 它主要用于遍历对象的属性。在上面的例子中,
key
会依次获取对象person
的属性名(name
、age
、city
),然后通过person[key]
来访问属性的值。 - 会遍历对象自身的以及继承的可枚举属性。如果只想遍历对象自身的属性,可以使用
hasOwnProperty
方法进行过滤,如if (person.hasOwnProperty(key)) {...}
。
- 它主要用于遍历对象的属性。在上面的例子中,
-
性能方面:
-
由于
for...in
会遍历对象的所有可枚举属性,包括原型链上的属性(如果不进行过滤),所以在性能上可能会比单纯遍历数组的for
循环稍慢。而且,它的遍历顺序可能因浏览器而异,不适合依赖特定顺序的遍历。
-
3. for...of
循环
-
基本语法:
for...of
循环用于遍历可迭代对象(如数组、字符串、Set
、Map
等)的值。语法是for (变量 of 可迭代对象) { 循环体语句 }
。例如,遍历一个数组:
let arr = [10, 20, 30];
for (let value of arr) {
console.log(value);
}
-
特点:
- 它直接遍历可迭代对象的值,不像
for...in
那样遍历对象的属性名。在数组的例子中,value
会依次获取数组中的每个元素。 - 对于自定义的可迭代对象,可以通过定义
Symbol.iterator
方法来使其能够被for...of
遍历。例如:
- 它直接遍历可迭代对象的值,不像
let myIterable = {
data: [1, 2, 3],
[Symbol.iterator]() {
let index = 0;
let self = this;
return {
next() {
if (index < self.data.length) {
return { value: self.data[index++], done: false };
} else {
return { done: true };
}
}
};
}
};
for (let value of myIterable) {
console.log(value);
}
-
性能方面:
-
for...of
在遍历数组等简单可迭代对象时,性能与for
循环相当。它提供了一种更简洁的方式来遍历值,特别是在处理现代 JavaScript 数据结构(如Set
、Map
)时,代码可读性更好。
-
4. forEach
方法(数组方法)
-
基本语法:
-
数组的
forEach
方法接受一个函数作为参数,该函数会在数组的每个元素上执行一次。语法是数组.forEach(函数)
。函数接收三个参数:当前元素、当前元素的索引、整个数组。例如:
-
let numbers = [1, 2, 3];
numbers.forEach((element, index, array) => {
console.log(`Element at index ${index} is ${element}`);
});
-
特点:
- 它是一种更函数式的遍历方式,不需要显式地管理索引。对于简单的操作,如对数组中的每个元素进行打印或修改,
forEach
方法很方便。 - 它没有返回值(或者说返回值是
undefined
),不能像map
等方法那样返回一个新的数组。如果需要返回新的数组,应该使用map
方法。
- 它是一种更函数式的遍历方式,不需要显式地管理索引。对于简单的操作,如对数组中的每个元素进行打印或修改,
-
性能方面:
-
forEach
方法的性能与for
循环类似,但在某些浏览器中可能会稍慢一点,因为它涉及到更多的函数调用开销。不过,这种性能差异在大多数情况下可以忽略不计。
-
5. map
方法(数组方法)
-
基本语法:
-
map
方法也接受一个函数作为参数,会对数组中的每个元素执行该函数,并返回一个新的数组,新数组的元素是函数的返回值。语法是数组.map(函数)
。例如:
-
let numbers = [1, 2, 3];
let doubled = numbers.map((element) => element * 2);
console.log(doubled);
-
特点:
- 它主要用于对数组中的每个元素进行转换,返回一个新的、经过转换后的数组。在上面的例子中,原数组
numbers
中的每个元素都被乘以 2,得到新数组doubled
。 - 不会改变原始数组,而是返回一个新的数组,这符合函数式编程的不可变数据原则,有助于避免一些副作用。
- 它主要用于对数组中的每个元素进行转换,返回一个新的、经过转换后的数组。在上面的例子中,原数组
-
性能方面:
-
由于
map
方法需要创建一个新的数组并返回,在性能上可能会比forEach
稍慢一些,特别是在处理大型数组时。但它提供了一种非常方便的方式来进行数据转换。
-
6. filter
方法(数组方法)
-
基本语法:
-
filter
方法接受一个函数作为参数,该函数用于判断数组中的元素是否符合条件,返回一个新的数组,其中包含符合条件的元素。语法是数组.filter(函数)
。例如:
-
let numbers = [1, 2, 3, 4, 5];
let evenNumbers = numbers.filter((element) => element % 2 === 0);
console.log(evenNumbers);
-
特点:
- 用于筛选数组中的元素,返回一个子集。在上面的例子中,只有偶数元素被筛选出来并组成新的数组
evenNumbers
。 - 同样不会改变原始数组,而是返回一个新的数组,这使得代码更具可维护性和可预测性。
- 用于筛选数组中的元素,返回一个子集。在上面的例子中,只有偶数元素被筛选出来并组成新的数组
-
性能方面:
- 与
map
类似,filter
需要遍历数组并根据条件判断是否添加元素到新数组中,所以在性能上也会有一定的开销。但在大多数情况下,它的性能是可以接受的,尤其是在数据量不是特别巨大的时候。
- 与