JavaScript 循环
在编程中,循环是一种基础且强大的结构,它允许我们重复执行特定的代码块,直到满足某个条件为止。JavaScript提供了多种循环方式,适用于不同的场景。掌握这些循环结构对于编写高效的JavaScript代码至关重要。
为什么需要循环?
想象一下,如果你需要打印数字1到100,没有循环的话,你需要写100行几乎相同的代码。使用循环,你只需几行代码就能完成同样的任务。循环使代码更简洁、更易于维护,同时也提高了程序的性能。
JavaScript 中的循环类型
JavaScript主要提供以下几种循环结构:
for
循环while
循环do-while
循环for...in
循环for...of
循环- 数组方法(如
forEach
、map
、filter
等)
让我们一一详细了解每种循环的使用方法和适用场景。
for循环
for
循环是最常用的循环类型之一,尤其当你知道循环需要执行的次数时。
基本语法
for (初始化; 条件; 递增/递减) {
// 循环体,当条件为true时执行
}
示例
// 打印1到5的数字
for (let i = 1; i <= 5; i++) {
console.log(i);
}
输出:
1
2
3
4
5
for循环的组成部分
- 初始化:在循环开始前执行一次,通常用于初始化计数器。
- 条件:在每次循环迭代前检查,如果为
true
则继续循环,否则退出循环。 - 递增/递减:在每次循环体执行后执行,通常用于更新计数器。
for
循环的三个部分都是可选的,但分号是必须的。例如,for (;;) { ... }
创建一个无限循环。
实际应用示例:遍历数组
const fruits = ['苹果', '香蕉', '橙子', '葡萄', '芒果'];
for (let i = 0; i < fruits.length; i++) {
console.log(`第${i+1}个水果是:${fruits[i]}`);
}
输出:
第1个水果是:苹果
第2个水果是:香蕉
第3个水果是:橙子
第4个水果是:葡萄
第5个水果是:芒果
while循环
while
循环在指定条件为真时重复执行代码块。它最适合当你不确定循环需要执行多少次时使用。
基本语法
while (条件) {
// 循环体,当条件为true时执行
}
示例
let i = 1;
while (i <= 5) {
console.log(i);
i++;
}
输出:
1
2
3
4
5
实际应用示例:猜数字游戏
const targetNumber = Math.floor(Math.random() * 10) + 1;
let guess = 0;
let attempts = 0;
// 模拟用户猜测,直到猜对为止
while (guess !== targetNumber) {
guess = Math.floor(Math.random() * 10) + 1; // 随机生成1-10的猜测数字
attempts++;
console.log(`尝试 #${attempts}: 猜测 ${guess}`);
}
console.log(`恭喜!猜对了目标数字 ${targetNumber},共用了 ${attempts} 次尝试。`);
使用while
循环时,务必确保循环条件最终会变为false
,否则将创建无限循环,可能导致浏览器或程序崩溃。
do-while循环
do-while
循环与while
循环相似,但它会先执行一次循环体,然后再检查条件。这确保循环体至少执行一次。
基本语法
do {
// 循环体,至少执行一次
} while (条件);
示例
let i = 1;
do {
console.log(i);
i++;
} while (i <= 5);
输出:
1
2
3
4
5
与while循环的区别
当条件一开始就为false
时,while
循环不会执行循环体,而do-while
循环会执行一次循环体。
let i = 6;
// while循环
while (i <= 5) {
console.log(`while: ${i}`);
i++;
}
// 重置i
i = 6;
// do-while循环
do {
console.log(`do-while: ${i}`);
i++;
} while (i <= 5);
输出:
do-while: 6
实际应用示例:用户输入验证
function simulateUserInput() {
// 模拟用户输入,随机返回一个有效或无效的值
return Math.random() > 0.5 ? "有效输入" : "";
}
let userInput;
let attempt = 0;
do {
attempt++;
userInput = simulateUserInput();
console.log(`尝试 #${attempt}: 用户输入为 "${userInput}"`);
} while (userInput === "");
console.log(`收到有效输入:${userInput},共尝试 ${attempt} 次`);
for...in 循环
for...in
循环主要用于遍历对象的属性。
基本语法
for (let key in object) {
// 使用key访问object[key]
}
示例:遍历对象属性
const person = {
firstName: "张",
lastName: "三",
age: 30,
city: "北京"
};
for (let key in person) {
console.log(`${key}: ${person[key]}`);
}
输出:
firstName: 张
lastName: 三
age: 30
city: 北京
不建议使用for...in
循环遍历数组,因为它也会遍历数组的非数字属性和原型链上的属性。如果要遍历数组,应使用for
循环、for...of
循环或数组方法。
for...of 循环
ES6引入的for...of
循环用于遍历可迭代对象(如数组、字符串、Map、Set等)。
基本语法
for (let value of iterable) {
// 使用value
}
示例:遍历数组
const fruits = ['苹果', '香蕉', '橙子'];
for (let fruit of fruits) {
console.log(fruit);
}
输出:
苹果
香蕉
橙子
示例:遍历字符串
const message = "Hello";
for (let char of message) {
console.log(char);
}
输出:
H
e
l
l
o
for...of 与 for...in 的区别
for...in
循环遍历对象的可枚举属性(键)。for...of
循环遍历可迭代对象的值。
const arr = ['a', 'b', 'c'];
// 添加一个非数字属性
arr.test = "不是数组元素";
// for...in遍历键(包括非数字属性)
for (let key in arr) {
console.log(`for...in: ${key} -> ${arr[key]}`);
}
// for...of只遍历值(不包括非数字属性)
for (let value of arr) {
console.log(`for...of: ${value}`);
}
输出:
for...in: 0 -> a
for...in: 1 -> b
for...in: 2 -> c
for...in: test -> 不是数组元素
for...of: a
for...of: b
for...of: c
数组迭代方法
除了传统的循环结构外,JavaScript数组还提供了多种内置方法用于迭代。这些方法更加简洁和功能化。
forEach()
forEach()
方法对数组的每个元素执行一次提供的函数。
const numbers = [1, 2, 3, 4, 5];
numbers.forEach(function(number, index) {
console.log(`索引 ${index} 的值是: ${number}`);
});
输出:
索引 0 的值是: 1
索引 1 的值是: 2
索引 2 的值是: 3
索引 3 的值是: 4
索引 4 的值是: 5
map()
map()
方法创建一个新数组,其结果是该数组中的每个元素调用一次提供的函数后的返回值。
const numbers = [1, 2, 3, 4, 5];
const doubled = numbers.map(function(number) {
return number * 2;
});
console.log("原始数组:", numbers);
console.log("加倍后:", doubled);
输出:
原始数组: [1, 2, 3, 4, 5]
加倍后: [2, 4, 6, 8, 10]
filter()
filter()
方法创建一个新数组,其包含通过所提供函数实现的测试的所有元素。
const numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
const evenNumbers = numbers.filter(function(number) {
return number % 2 === 0;
});
console.log("所有数字:", numbers);
console.log("偶数:", evenNumbers);
输出:
所有数字: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
偶数: [2, 4, 6, 8, 10]
其他数组方法
JavaScript还有其他有用的数组迭代方法,如reduce()
、some()
、every()
等。这些方法各自有特定的用途,值得学习掌握。
循环控制语句
JavaScript提供了两个特殊的语句来控制循环的执行流程:break
和continue
。
break
break
语句用于完全终止当前循环。
for (let i = 1; i <= 10; i++) {
if (i === 5) {
console.log("遇到数字5,终止循环");
break;
}
console.log(i);
}
输出:
1
2
3
4
遇到数字5,终止循环
continue
continue
语句用于跳过当前迭代,直接进入下一次迭代。
for (let i = 1; i <= 5; i++) {
if (i === 3) {
console.log("跳过数字3");
continue;
}
console.log(i);
}
输出:
1
2
跳过数字3
4
5
嵌套循环
可以在一个循环内部包含另一个循环,这称为嵌套循环。外层循环的每次迭代都会完整执行一次内层循环。
// 打印乘法表(1-5)
for (let i = 1; i <= 5; i++) {
let row = "";
for (let j = 1; j <= 5; j++) {
row += `${i}x${j}=${i*j}\t`;
}
console.log(row);
}
输出:
1x1=1 1x2=2 1x3=3 1x4=4 1x5=5
2x1=2 2x2=4 2x3=6 2x4=8 2x5=10
3x1=3 3x2=6 3x3=9 3x4=12 3x5=15
4x1=4 4x2=8 4x3=12 4x4=16 4x5=20
5x1=5 5x2=10 5x3=15 5x4=20 5x5=25
嵌套循环的时间复杂度是外层循环次数乘以内层循环次数,例如上面的例子复杂度为O(n²),当数据量大时要谨慎使用。
循环的性能考虑
不同的循环在性能上有细微差别,但对于大多数应用来说,选择循环类型更应基于代码清晰度和适用场景,而不是微小的性能差异。
一般来说:
- 传统的
for
循环通常是最快的,特别是当你需要控制步长时。 - 数组方法(如
forEach
、map
等)虽然可能稍慢,但代码更简洁、更容易理解。 - 避免在循环中修改循环变量(除了循环控制语句)。
- 当处理大数据集时,考虑使用
for
循环而非forEach
以获得更好的性能。
实际应用案例:购物车总价计算
下面是一个使用循环处理购物车数据的实例,展示了几种不同循环方式的应用:
const cart = [
{ name: "T恤", price: 99, quantity: 2 },
{ name: "牛仔裤", price: 199, quantity: 1 },
{ name: "运动鞋", price: 299, quantity: 1 },
{ name: "帽子", price: 59, quantity: 3 }
];
// 使用for循环计算总价
let totalWithFor = 0;
for (let i = 0; i < cart.length; i++) {
totalWithFor += cart[i].price * cart[i].quantity;
}
console.log(`使用for循环计算的总价: ¥${totalWithFor}`);
// 使用for...of循环计算总价
let totalWithForOf = 0;
for (let item of cart) {
totalWithForOf += item.price * item.quantity;
}
console.log(`使用for...of循环计算的总价: ¥${totalWithForOf}`);
// 使用forEach计算总价
let totalWithForEach = 0;
cart.forEach(item => {
totalWithForEach += item.price * item.quantity;
});
console.log(`使用forEach计算的总价: ¥${totalWithForEach}`);
// 使用reduce计算总价
const totalWithReduce = cart.reduce((sum, item) => {
return sum + (item.price * item.quantity);
}, 0);
console.log(`使用reduce计算的总价: ¥${totalWithReduce}`);
输出:
使用for循环计算的总价: ¥873
使用for...of循环计算的总价: ¥873
使用forEach计算的总价: ¥873
使用reduce计算的总价: ¥873
总结
循环是JavaScript编程的基础构建块之一,掌握不同类型的循环及其适用场景对于编写高效的代码至关重要:
- for循环:当你知道循环需要执行的精确次数时使用。
- while循环:当你不知道循环需要执行多少次但知道循环条件时使用。
- do-while循环:当你需要循环体至少执行一次时使用。
- for...in循环:用于遍历对象的属性。
- for...of循环:用于遍历数组或其他可迭代对象的值。
- 数组方法:如
forEach
、map
、filter
等,提供了更简洁、更功能化的迭代方式。
选择合适的循环类型可以使代码更简洁、更易于理解和维护。
练习题
为了巩固对循环的理解,尝试完成以下练习:
- 使用
for
循环打印出1到100之间的所有偶数。 - 使用
while
循环计算1到10的所有整数之和。 - 使用
for...of
循环找出数组[12, 5, 8, 130, 44]
中的最大值。 - 使用
filter
和map
方法筛选出数组[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
中的偶数并将它们加倍。 - 编写一个函数,接收一个正整数n,并使用循环打印出n阶乘的结果。
进阶资源
通过持续练习和应用,你将能够熟练运用JavaScript中的各种循环结构,编写更高效、更简洁的代码。