JavaScript 循环语句

概述

循环语句用于重复执行代码块,直到满足特定条件。JavaScript提供了多种循环结构,适用于不同的使用场景。

for 循环

基本语法

for (初始化; 条件; 更新表达式) {
    // 循环体
}

基础用法

// 经典的计数循环
for (let i = 0; i < 5; i++) {
    console.log(`计数: ${i}`);
}
 
// 倒序循环
for (let i = 10; i > 0; i--) {
    console.log(`倒计时: ${i}`);
}
 
// 步长为2的循环
for (let i = 0; i < 10; i += 2) {
    console.log(`偶数位置: ${i}`);
}

数组遍历

const fruits = ['apple', 'banana', 'orange'];
 
// 传统方式
for (let i = 0; i < fruits.length; i++) {
    console.log(`索引${i}: ${fruits[i]}`);
}
 
// 性能优化版本(缓存长度)
for (let i = 0, len = fruits.length; i < len; i++) {
    console.log(`索引${i}: ${fruits[i]}`);
}

特殊用法

// 无限循环(需要break跳出)
for (;;) {
    if (someCondition) break;
    // 执行某些操作
}
 
// 多变量初始化
for (let i = 0, j = 10; i < j; i++, j--) {
    console.log(`i=${i}, j=${j}`);
}

while 循环

基本语法

while (条件) {
    // 循环体
}

使用场景

// 条件未知的循环
let count = 0;
while (count < 5) {
    console.log(`计数: ${count}`);
    count++;
}
 
// 用户输入验证
let userInput;
while (userInput !== 'quit') {
    userInput = prompt('输入命令(输入quit退出):');
    if (userInput !== 'quit') {
        console.log(`你输入了: ${userInput}`);
    }
}
 
// 数组处理
const numbers = [1, 2, 3, 4, 5];
let index = 0;
while (index < numbers.length) {
    if (numbers[index] % 2 === 0) {
        console.log(`偶数: ${numbers[index]}`);
    }
    index++;
}

防止无限循环

// 危险:忘记更新条件变量
let i = 0;
while (i < 10) {
    console.log(i);
    // 忘记了 i++ ,会造成无限循环!
}
 
// 安全:确保条件会改变
let i = 0;
while (i < 10) {
    console.log(i);
    i++;  // 确保循环会结束
}
 
// 使用计数器防护
let attempts = 0;
const maxAttempts = 100;
while (someCondition && attempts < maxAttempts) {
    // 执行操作
    attempts++;
}

do-while 循环

基本语法

do {
    // 循环体
} while (条件);

使用场景

// 至少执行一次的场景
let userChoice;
do {
    userChoice = prompt('请选择操作(1-3):');
    console.log(`你选择了: ${userChoice}`);
} while (userChoice !== '3');
 
// 游戏循环
let playAgain;
do {
    playGame();
    playAgain = confirm('再玩一次吗?');
} while (playAgain);
 
// 数据验证
let password;
do {
    password = prompt('请输入密码(至少6位):');
    if (password.length < 6) {
        alert('密码太短,请重新输入!');
    }
} while (password.length < 6);

for…in 循环

基本语法

for (变量 in 对象) {
    // 循环体
}

对象属性遍历

const person = {
    name: 'John',
    age: 30,
    city: 'New York'
};
 
// 遍历对象属性
for (const key in person) {
    console.log(`${key}: ${person[key]}`);
}
 
// 安全遍历(过滤继承属性)
for (const key in person) {
    if (person.hasOwnProperty(key)) {
        console.log(`${key}: ${person[key]}`);
    }
}
 
// 现代方法:使用Object.keys()
Object.keys(person).forEach(key => {
    console.log(`${key}: ${person[key]}`);
});

数组遍历注意事项

const arr = ['a', 'b', 'c'];
arr.customProperty = 'custom';
 
// for...in会遍历所有可枚举属性(包括非数字索引)
for (const index in arr) {
    console.log(`${index}: ${arr[index]}`);
}
// 输出: 0: a, 1: b, 2: c, customProperty: custom
 
// 对于数组,推荐使用for循环或for...of
for (let i = 0; i < arr.length; i++) {
    console.log(`${i}: ${arr[i]}`);
}
// 输出: 0: a, 1: b, 2: c

for…of 循环

基本语法

for (变量 of 可迭代对象) {
    // 循环体
}

数组遍历

const fruits = ['apple', 'banana', 'orange'];
 
// 遍历数组值
for (const fruit of fruits) {
    console.log(fruit);
}
 
// 同时获取索引和值
for (const [index, fruit] of fruits.entries()) {
    console.log(`${index}: ${fruit}`);
}
 
// 过滤遍历
for (const fruit of fruits) {
    if (fruit.startsWith('a')) {
        console.log(`以a开头的水果: ${fruit}`);
    }
}

字符串遍历

const text = "Hello";
 
for (const char of text) {
    console.log(char);  // H e l l o
}
 
// 处理Unicode字符
const emoji = "👨‍👩‍👧‍👦";
for (const char of emoji) {
    console.log(char);  // 正确处理复合Unicode字符
}

其他可迭代对象

// Set遍历
const uniqueNumbers = new Set([1, 2, 3, 2, 1]);
for (const num of uniqueNumbers) {
    console.log(num);  // 1, 2, 3
}
 
// Map遍历
const userRoles = new Map([
    ['john', 'admin'],
    ['jane', 'user'],
    ['bob', 'moderator']
]);
 
for (const [user, role] of userRoles) {
    console.log(`${user}: ${role}`);
}
 
// NodeList遍历
const elements = document.querySelectorAll('.item');
for (const element of elements) {
    element.style.color = 'red';
}

循环控制语句

break语句

// 跳出循环
for (let i = 0; i < 10; i++) {
    if (i === 5) {
        break;  // 当i=5时跳出循环
    }
    console.log(i);  // 输出: 0, 1, 2, 3, 4
}
 
// 在嵌套循环中使用标签
outerLoop: for (let i = 0; i < 3; i++) {
    for (let j = 0; j < 3; j++) {
        if (i === 1 && j === 1) {
            break outerLoop;  // 跳出外层循环
        }
        console.log(`i=${i}, j=${j}`);
    }
}

continue语句

// 跳过当前迭代
for (let i = 0; i < 5; i++) {
    if (i === 2) {
        continue;  // 跳过i=2的迭代
    }
    console.log(i);  // 输出: 0, 1, 3, 4
}
 
// 过滤偶数
for (let i = 0; i < 10; i++) {
    if (i % 2 === 0) {
        continue;  // 跳过偶数
    }
    console.log(`奇数: ${i}`);
}

循环性能优化

1. 缓存数组长度

// 低效:每次迭代都计算长度
for (let i = 0; i < arr.length; i++) {
    // 处理arr[i]
}
 
// 高效:缓存长度
for (let i = 0, len = arr.length; i < len; i++) {
    // 处理arr[i]
}

2. 选择合适的循环类型

const numbers = [1, 2, 3, 4, 5];
 
// 需要索引:使用传统for循环
for (let i = 0; i < numbers.length; i++) {
    console.log(`索引${i}: ${numbers[i]}`);
}
 
// 只需要值:使用for...of
for (const num of numbers) {
    console.log(num);
}
 
// 函数式方法:更简洁但可能略慢
numbers.forEach((num, index) => {
    console.log(`索引${index}: ${num}`);
});

3. 避免在循环中创建函数

// 低效:在循环中创建函数
for (let i = 0; i < 1000; i++) {
    setTimeout(function() {
        console.log(i);
    }, 100);
}
 
// 高效:在循环外定义函数
function logNumber(num) {
    console.log(num);
}
 
for (let i = 0; i < 1000; i++) {
    setTimeout(() => logNumber(i), 100);
}

现代循环方法

数组方法替代循环

const numbers = [1, 2, 3, 4, 5];
 
// forEach: 遍历每个元素
numbers.forEach((num, index) => {
    console.log(`索引${index}: ${num}`);
});
 
// map: 转换数组
const doubled = numbers.map(num => num * 2);
 
// filter: 过滤数组
const evenNumbers = numbers.filter(num => num % 2 === 0);
 
// find: 查找元素
const found = numbers.find(num => num > 3);
 
// some/every: 测试条件
const hasEven = numbers.some(num => num % 2 === 0);
const allPositive = numbers.every(num => num > 0);
 
// reduce: 累积操作
const sum = numbers.reduce((total, num) => total + num, 0);

最佳实践

1. 选择合适的循环类型

  • for: 需要精确控制循环过程
  • while: 条件复杂或不确定循环次数
  • do-while: 至少执行一次循环体
  • for…in: 遍历对象属性
  • for…of: 遍历可迭代对象的值

2. 避免无限循环

// 添加防护措施
let attempts = 0;
const maxAttempts = 1000;
 
while (condition && attempts < maxAttempts) {
    // 循环体
    attempts++;
}
 
if (attempts === maxAttempts) {
    console.warn('循环达到最大尝试次数');
}

3. 及时跳出循环

// 找到目标后立即跳出
function findUser(users, targetId) {
    for (const user of users) {
        if (user.id === targetId) {
            return user;  // 找到后立即返回
        }
    }
    return null;  // 未找到
}

4. 使用描述性的变量名

// 不好
for (let i = 0; i < arr.length; i++) {
    // 处理arr[i]
}
 
// 更好
for (let userIndex = 0; userIndex < users.length; userIndex++) {
    const currentUser = users[userIndex];
    // 处理currentUser
}
 
// 最好(使用for...of)
for (const currentUser of users) {
    // 处理currentUser
}

上一篇:条件语句 | 下一篇:函数