JS常见的循环大集合

77 阅读5分钟

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的属性名(nameagecity),然后通过person[key]来访问属性的值。
    • 会遍历对象自身的以及继承的可枚举属性。如果只想遍历对象自身的属性,可以使用hasOwnProperty方法进行过滤,如if (person.hasOwnProperty(key)) {...}
  • 性能方面

    • 由于for...in会遍历对象的所有可枚举属性,包括原型链上的属性(如果不进行过滤),所以在性能上可能会比单纯遍历数组的for循环稍慢。而且,它的遍历顺序可能因浏览器而异,不适合依赖特定顺序的遍历。

3. for...of循环

  • 基本语法

    • for...of循环用于遍历可迭代对象(如数组、字符串、SetMap等)的值。语法是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 数据结构(如SetMap)时,代码可读性更好。

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需要遍历数组并根据条件判断是否添加元素到新数组中,所以在性能上也会有一定的开销。但在大多数情况下,它的性能是可以接受的,尤其是在数据量不是特别巨大的时候。