循环

JavaScript 中的 for 循环有多种语法,适用于不同的场景。这些语法包括传统的 for 循环、for-in 循环、for-of 循环等。每种 for 循环语法都有其特定的用法和适用范围。让我们来看一下这些循环语法及其使用方式。

1. 传统 for 循环

传统的 for 循环用于在固定次数内迭代,或通过迭代变量控制循环。它由初始化部分、条件部分、迭代部分和循环体组成。

for (initialization; condition; iteration) { // setup执行一次; 每次比较,true才会进入循环; 每次做完循环体后要做的事情
    // loop body
}
  • initialization: 循环开始前执行的代码,用于初始化循环变量。
  • condition: 在每次循环迭代之前进行测试。如果结果为 true,则继续循环;如果为 false,则结束循环。
  • iteration: 在每次循环迭代结束时执行的代码,通常用于更新循环变量。

使用场景

for 循环适用于需要固定次数迭代的场景,例如遍历数组、执行固定次数的操作等。由于 let 声明的变量具有块级作用域,在循环结束后,i 不再可用,这在某种程度上防止了循环变量泄露。

注意事项

  • 当循环条件永远不会变为 false 时,可能导致无限循环。
  • 过多的循环迭代可能导致性能问题,因此要确保循环终止条件正确。
  • 使用块级作用域的循环变量可以避免变量泄露,确保代码的局部性。

示例1

(let i = 0; i < 10; i++) 是一种常见的 for 循环结构,通常用于在固定次数内循环执行代码。

for (let i=0; i<10; i++) {
    console.log(i)
}
/*
0
1
2
3
4
5
6
7
8
9
*/

(let i = 0; i < 10; i++)

  1. let i = 0

    • 在循环开始时执行。let 关键字用于声明循环变量 i,并初始化为 0
    • 这种初始化在 for 循环的范围内有效,这意味着在循环外 i 不可访问。
  2. i < 10

    • 这是循环条件。在每次迭代前检查 i 是否小于 10。如果条件为 true,循环继续;否则循环结束。
    • 由于初始化为 0,且在每次迭代后 i 增加 1,循环总共执行 10 次。
  3. i++

    • 这是迭代部分。在每次循环结束时,i++i 增加 1。这部分代码确保循环变量随着迭代而递增。
    • 由于这是后置递增,i 先被使用后增加。

循环的执行过程

  • 循环开始时,执行 let i = 0 初始化。
  • 然后检查循环条件 i < 10,如果条件为 true,继续执行循环体。
  • 循环体执行后,执行 i++,将 i 增加 1
  • 接着再次检查 i < 10,如果仍为 true,继续迭代;如果为 false,循环结束。

示例2

for (let i=0,j=9; i<10; i++,j--) {
    console.log(i * j)
}
/*
0
8
14
18
20
20
18
14
8
0
*/

示例3(打印偶数)

for (let i=0; i<10; i+=2) {
    console.log(i)
}
/*
0
2
4
6
8
*/

for (let i=0; i<10; i++) {
    console.log(i++)
}
/*
0
2
4
6
8
*/

示例4(打印奇数)

for (let i=1; i<10; i+=2) {
    console.log(i)
}
/*
1
3
5
7
9
*/

for (let i=0; i<10; i++) {
    console.log(++i)
}
/*
1
3
5
7
9
*/

2. for-in 循环

for-in 循环用于遍历对象的可枚举属性。它不适用于数组遍历,因为 for-in 循环遍历的顺序并不保证按照数组索引顺序。

const person = {
  name: 'John',
  age: 25,
  country: 'USA'
};

for (let key in person) {
  console.log(`${key}: ${person[key]}`);
}

在这个例子中,for-in 循环遍历对象的属性名,并且可以通过 person[key] 获取相应的值。

注意事项

let arr = [10, 20, 30, 40];

for (let x in arr) {
    console.log(x, arr[x]);
}
/*
0 10
1 20
2 30
3 40
*/

for-in 循环用于遍历对象的可枚举属性。虽然它可以用于遍历数组,但这种用法通常不被推荐,原因在于 for-in 循环在遍历对象属性时没有保证顺序的规范。事实上,for-in 在实际使用中经常按顺序遍历数组,但并不是必定的,因为 JavaScript 对象的属性顺序是根据 ECMAScript 规范的具体实现和版本而定的。

可能的问题

  1. 不保证遍历顺序 虽然 for-in 循环在遍历数组时往往遵循索引顺序,但并不能确保总是如此,特别是在复杂对象或添加自定义属性的情况下。

  2. 可能包括原型链上的属性 for-in 循环会遍历对象的所有可枚举属性,包括原型链上的属性。如果数组继承了某些属性,可能会在 for-in 中被遍历到。

  3. 可能导致意外结果 使用 for-in 遍历数组时,增加或删除数组的元素或在数组上添加自定义属性,可能导致遍历结果不一致。

正确使用 for-in 循环的场景

for-in 循环主要用于遍历对象的属性,不适合用来遍历数组。适合的场景包括:

  • 遍历对象的属性

    const person = {
      name: 'John',
      age: 30,
      country: 'USA'
    };
    
    for (let key in person) {
      console.log(key, person[key]);
    }

推荐的数组遍历方式

对于遍历数组,建议使用 for-of 循环、传统 for 循环或其他数组迭代方法,如 forEach,因为这些方法确保了顺序并且不会遍历原型链上的属性。

  • for-of 循环

    const arr = [10, 20, 30, 40];
    
    for (const value of arr) {
      console.log(value);
    }
  • 传统 for 循环

    const arr = [10, 20, 30, 40];
    
    for (let i = 0; i < arr.length; i++) {
      console.log(arr[i]);
    }

总结

虽然 for-in 循环可以用于遍历数组,但它并不是最佳实践,因为它不保证遍历顺序并可能包含原型链上的属性。为了确保数组的正确遍历和顺序,应使用 for-of、传统 for 循环或 forEach 等方法,这些方法在遍历数组时更加可靠。

3. for-of 循环

for-of 循环用于遍历可迭代对象,包括数组、字符串、MapSet 等。它适用于数组的顺序遍历。

const colors = ['red', 'green', 'blue'];

for (const color of colors) {
  console.log(color);
}

在这个例子中,for-of 循环遍历数组 colors 的每个元素。

使用场景

  • 传统 for 循环:适用于需要控制迭代次数或通过条件来决定循环次数的场景。
  • for-in 循环:用于遍历对象的属性,适合操作对象的属性名及其值。
  • for-of 循环:用于遍历可迭代对象,适合顺序遍历数组或其他可迭代集合。

注意事项

  • 对于数组遍历,建议使用 for-of 而不是 for-in,因为 for-in 可能遍历原型链上的属性,且遍历顺序不一定与数组索引顺序一致。
  • for-of 无法用于遍历对象的属性,因为对象不是可迭代对象。
  • for-in 可能返回非标准的属性顺序,因此在需要保证顺序的场景下应谨慎使用。

总结

JavaScript 中的 for 循环语法多种多样,每种风格都有其特定的用途和最佳实践。理解不同语法的特点和适用场景可以帮助你选择最佳的循环方式,从而编写简洁、高效且易于维护的代码。

JavaScript 中的 while 循环用于在满足条件的情况下重复执行代码块。while 循环的语法包括两种主要形式:基本的 while 循环和 do-while 循环。让我们详细解释这两种循环及其用法。

1. 基本 while 循环

while 循环在每次迭代前检查条件,如果条件为 true,则继续执行循环体;如果为 false,循环终止。

while (condition) {
    // 执行循环体
}
  • condition 是布尔表达式,决定是否继续循环。
  • 循环体是 { ... } 中的代码块,只要条件为 true,循环体就会执行。

示例1

let x = 10;

while (x--) {
    console.log(x);
}

/*
9
8
7
6
5
4
3
2
1
0
*/

示例2

let i = 0;

while (i < 5) {
    console.log(i);
    i++; // 记得更新循环变量,否则会导致无限循环
}

在这个例子中,i 作为循环变量,每次循环后递增 1,并且在每次迭代前检查 i < 5 是否为真。

2. do-while 循环

do-while 循环首先执行循环体,然后检查条件。如果条件为 true,继续循环;否则终止。do-while 循环至少会执行一次。

do {
    // 执行循环体
} while (condition);

在这个语法中:

  • 循环体先执行一次,然后检查条件。
  • condition 是布尔表达式,决定是否继续循环。

示例

let j = 0;

do {
    console.log(j);
    j++; // 更新循环变量
} while (j < 5);

在这个例子中,即使 conditionfalse,循环体至少会执行一次。这与基本的 while 循环的区别在于 do-while 先执行循环体,后检查条件。

使用场景

  • 基本 while 循环:当需要在每次迭代前检查条件时使用,适用于需要根据条件重复执行代码块的场景。
  • do-while 循环:当需要至少执行一次循环体,然后再检查条件时使用,适用于需要确保循环体至少执行一次的场景。

注意事项

  • 确保循环条件最终会变成 false,以避免无限循环。在 while 循环中,要确保循环体中有适当的更新逻辑,使循环变量能够满足终止条件。
  • 使用 while 循环时要特别小心,确保循环变量的更新逻辑正确,以防止代码陷入无限循环。

总结

JavaScript 中的 while 循环主要有两种语法:基本 whiledo-while。理解这两种循环的工作原理和使用场景,有助于在编写重复逻辑时选择适当的循环方式。确保循环有明确的终止条件,以避免无限循环。