Appearance
TypeScript 循环结构
循环结构是编程中常用的控制结构,用于重复执行一段代码。TypeScript 支持与 JavaScript 相同的循环结构,包括 for 循环、for-in 循环、for-of 循环、while 循环和 do-while 循环。本文将详细介绍 TypeScript 中的循环结构。
1. for 循环
for 循环是最常用的循环结构,用于在指定条件下重复执行代码。
语法
typescript
for (初始化表达式; 条件表达式; 更新表达式) {
// 循环体代码
}示例
typescript
// 打印 1 到 5 的数字
for (let i = 1; i <= 5; i++) {
console.log(i);
}
// 输出:
// 1
// 2
// 3
// 4
// 5嵌套 for 循环
typescript
// 打印乘法表
for (let i = 1; i <= 9; i++) {
for (let j = 1; j <= i; j++) {
console.log(`${j} * ${i} = ${j * i}`);
}
console.log('---');
}2. for-in 循环
for-in 循环用于遍历对象的可枚举属性。
语法
typescript
for (let 变量 in 对象) {
// 循环体代码
}示例
typescript
// 遍历对象的属性
const person = {
name: "John",
age: 30,
city: "New York"
};
for (let key in person) {
console.log(`${key}: ${person[key]}`);
}
// 输出:
// name: John
// age: 30
// city: New York
// 遍历数组的索引
const fruits = ["apple", "banana", "cherry"];
for (let index in fruits) {
console.log(`${index}: ${fruits[index]}`);
}
// 输出:
// 0: apple
// 1: banana
// 2: cherry注意事项
for-in循环会遍历对象的所有可枚举属性,包括继承的属性。- 对于数组,
for-in循环遍历的是数组的索引,而不是元素值。 - 为了避免遍历到继承的属性,可以使用
hasOwnProperty方法进行检查。
typescript
// 使用 hasOwnProperty 检查
const person = {
name: "John",
age: 30,
city: "New York"
};
for (let key in person) {
if (person.hasOwnProperty(key)) {
console.log(`${key}: ${person[key]}`);
}
}3. for-of 循环
for-of 循环用于遍历可迭代对象(如数组、字符串、Map、Set 等)的元素。
语法
typescript
for (let 变量 of 可迭代对象) {
// 循环体代码
}示例
typescript
// 遍历数组的元素
const fruits = ["apple", "banana", "cherry"];
for (let fruit of fruits) {
console.log(fruit);
}
// 输出:
// apple
// banana
// cherry
// 遍历字符串的字符
const str = "Hello";
for (let char of str) {
console.log(char);
}
// 输出:
// H
// e
// l
// l
// o
// 遍历 Map 的条目
const map = new Map();
map.set("name", "John");
map.set("age", 30);
for (let [key, value] of map) {
console.log(`${key}: ${value}`);
}
// 输出:
// name: John
// age: 30
// 遍历 Set 的元素
const set = new Set([1, 2, 3, 4, 5]);
for (let item of set) {
console.log(item);
}
// 输出:
// 1
// 2
// 3
// 4
// 5注意事项
for-of循环只能用于可迭代对象。- 对于数组,
for-of循环遍历的是数组的元素值,而不是索引。 for-of循环不能直接遍历对象,需要使用Object.entries()、Object.keys()或Object.values()方法。
typescript
// 遍历对象的键值对
const person = {
name: "John",
age: 30,
city: "New York"
};
// 使用 Object.entries()
for (let [key, value] of Object.entries(person)) {
console.log(`${key}: ${value}`);
}
// 使用 Object.keys()
for (let key of Object.keys(person)) {
console.log(`${key}: ${person[key]}`);
}
// 使用 Object.values()
for (let value of Object.values(person)) {
console.log(value);
}4. while 循环
while 循环用于在条件为真时重复执行代码。
语法
typescript
while (条件) {
// 循环体代码
}示例
typescript
// 打印 1 到 5 的数字
let i = 1;
while (i <= 5) {
console.log(i);
i++;
}
// 输出:
// 1
// 2
// 3
// 4
// 5注意事项
- 确保循环条件最终会变为 false,否则会导致无限循环。
- 循环体中必须包含更新循环变量的代码,否则会导致无限循环。
typescript
// 无限循环(危险)
// while (true) {
// console.log("无限循环");
// }5. do-while 循环
do-while 循环与 while 循环类似,但它会先执行一次循环体,然后再检查条件。
语法
typescript
do {
// 循环体代码
} while (条件);示例
typescript
// 打印 1 到 5 的数字
let i = 1;
do {
console.log(i);
i++;
} while (i <= 5);
// 输出:
// 1
// 2
// 3
// 4
// 5
// 即使条件为假,也会执行一次循环体
let j = 6;
do {
console.log(j);
j++;
} while (j <= 5);
// 输出:
// 66. 循环控制语句
break 语句
break 语句用于跳出循环,终止循环的执行。
typescript
// 使用 break 跳出循环
for (let i = 1; i <= 10; i++) {
if (i === 5) {
break;
}
console.log(i);
}
// 输出:
// 1
// 2
// 3
// 4continue 语句
continue 语句用于跳过当前循环的剩余部分,进入下一次循环。
typescript
// 使用 continue 跳过偶数
for (let i = 1; i <= 10; i++) {
if (i % 2 === 0) {
continue;
}
console.log(i);
}
// 输出:
// 1
// 3
// 5
// 7
// 9label 语句
label 语句用于标记循环,配合 break 或 continue 语句使用,可以跳出或继续指定的循环。
typescript
// 使用 label 跳出嵌套循环
outerLoop: for (let i = 1; i <= 3; i++) {
for (let j = 1; j <= 3; j++) {
if (i === 2 && j === 2) {
break outerLoop;
}
console.log(`i: ${i}, j: ${j}`);
}
}
// 输出:
// i: 1, j: 1
// i: 1, j: 2
// i: 1, j: 3
// i: 2, j: 17. 数组方法
TypeScript 中的数组提供了一些方法,可以替代传统的循环结构,使代码更简洁、更易读。
forEach 方法
forEach 方法用于遍历数组的每个元素,并对每个元素执行指定的函数。
typescript
const fruits = ["apple", "banana", "cherry"];
fruits.forEach((fruit, index) => {
console.log(`${index}: ${fruit}`);
});
// 输出:
// 0: apple
// 1: banana
// 2: cherrymap 方法
map 方法用于遍历数组的每个元素,并返回一个新的数组,新数组的元素是原数组元素经过指定函数处理后的结果。
typescript
const numbers = [1, 2, 3, 4, 5];
const doubledNumbers = numbers.map(num => num * 2);
console.log(doubledNumbers); // 输出:[2, 4, 6, 8, 10]filter 方法
filter 方法用于遍历数组的每个元素,并返回一个新的数组,新数组的元素是原数组中满足指定条件的元素。
typescript
const numbers = [1, 2, 3, 4, 5];
const evenNumbers = numbers.filter(num => num % 2 === 0);
console.log(evenNumbers); // 输出:[2, 4]reduce 方法
reduce 方法用于遍历数组的每个元素,并将其累加到一个累加器中,返回最终的累加结果。
typescript
const numbers = [1, 2, 3, 4, 5];
const sum = numbers.reduce((acc, num) => acc + num, 0);
console.log(sum); // 输出:15some 方法
some 方法用于检查数组中是否至少有一个元素满足指定条件。
typescript
const numbers = [1, 2, 3, 4, 5];
const hasEven = numbers.some(num => num % 2 === 0);
console.log(hasEven); // 输出:trueevery 方法
every 方法用于检查数组中是否所有元素都满足指定条件。
typescript
const numbers = [1, 2, 3, 4, 5];
const allPositive = numbers.every(num => num > 0);
console.log(allPositive); // 输出:truefind 方法
find 方法用于查找数组中第一个满足指定条件的元素。
typescript
const numbers = [1, 2, 3, 4, 5];
const firstEven = numbers.find(num => num % 2 === 0);
console.log(firstEven); // 输出:2findIndex 方法
findIndex 方法用于查找数组中第一个满足指定条件的元素的索引。
typescript
const numbers = [1, 2, 3, 4, 5];
const firstEvenIndex = numbers.findIndex(num => num % 2 === 0);
console.log(firstEvenIndex); // 输出:18. 最佳实践
1. 选择合适的循环结构
- 对于已知循环次数的情况,使用
for循环。 - 对于遍历对象的属性,使用
for-in循环。 - 对于遍历可迭代对象的元素,使用
for-of循环。 - 对于条件循环,使用
while或do-while循环。 - 对于数组操作,优先使用数组方法(如
forEach、map、filter等)。
2. 避免无限循环
确保循环条件最终会变为 false,循环体中包含更新循环变量的代码。
typescript
// 错误(无限循环)
// let i = 1;
// while (i <= 5) {
// console.log(i);
// // 没有更新 i
// }
// 正确
let i = 1;
while (i <= 5) {
console.log(i);
i++;
}3. 保持循环简洁
循环体应该简洁明了,避免过于复杂的逻辑。如果循环体过长,可以考虑将其提取为一个函数。
typescript
// 推荐
function processItem(item) {
// 处理逻辑
console.log(item);
}
const items = [1, 2, 3, 4, 5];
for (let item of items) {
processItem(item);
}
// 不推荐
const items = [1, 2, 3, 4, 5];
for (let item of items) {
// 复杂的处理逻辑
console.log(item);
// 更多代码...
}4. 使用类型注解
在 TypeScript 中,为循环变量添加类型注解可以提高代码的可读性和类型安全性。
typescript
// 推荐
const numbers: number[] = [1, 2, 3, 4, 5];
for (let num: number of numbers) {
console.log(num);
}
// 不推荐
const numbers = [1, 2, 3, 4, 5];
for (let num of numbers) {
console.log(num);
}5. 避免在循环中修改数组
在遍历数组时,避免修改数组的长度或内容,否则可能会导致意外的行为。
typescript
// 错误(在循环中修改数组)
const numbers = [1, 2, 3, 4, 5];
for (let i = 0; i < numbers.length; i++) {
if (numbers[i] === 3) {
numbers.splice(i, 1); // 删除元素,会影响数组长度
}
console.log(numbers[i]);
}
// 正确(先创建新数组)
const numbers = [1, 2, 3, 4, 5];
const filteredNumbers = numbers.filter(num => num !== 3);
for (let num of filteredNumbers) {
console.log(num);
}9. 常见错误
1. 无限循环
忘记更新循环变量或循环条件永远为真,导致无限循环。
typescript
// 错误(无限循环)
// for (let i = 1; ; i++) {
// console.log(i);
// }
// 错误(无限循环)
// let i = 1;
// while (true) {
// console.log(i);
// }2. 循环变量作用域问题
在使用 var 声明循环变量时,由于 var 是函数作用域,可能会导致循环变量共享的问题。
typescript
// 错误(循环变量共享)
for (var i = 0; i < 5; i++) {
setTimeout(() => {
console.log(i); // 输出:5, 5, 5, 5, 5
}, 100);
}
// 正确(使用 let 声明循环变量)
for (let i = 0; i < 5; i++) {
setTimeout(() => {
console.log(i); // 输出:0, 1, 2, 3, 4
}, 100);
}3. 混淆 for-in 和 for-of
for-in 循环遍历的是对象的属性或数组的索引,而 for-of 循环遍历的是可迭代对象的元素。
typescript
const fruits = ["apple", "banana", "cherry"];
// 错误(使用 for-in 遍历数组元素)
for (let fruit in fruits) {
console.log(fruit); // 输出:0, 1, 2(索引)
}
// 正确(使用 for-of 遍历数组元素)
for (let fruit of fruits) {
console.log(fruit); // 输出:apple, banana, cherry(元素)
}4. 数组方法的使用错误
在使用数组方法时,需要注意方法的返回值和参数。
typescript
const numbers = [1, 2, 3, 4, 5];
// 错误(forEach 方法没有返回值)
// const doubledNumbers = numbers.forEach(num => num * 2);
// console.log(doubledNumbers); // 输出:undefined
// 正确(使用 map 方法)
const doubledNumbers = numbers.map(num => num * 2);
console.log(doubledNumbers); // 输出:[2, 4, 6, 8, 10]总结
TypeScript 支持多种循环结构,包括:
- for 循环:用于在指定条件下重复执行代码
- for-in 循环:用于遍历对象的可枚举属性
- for-of 循环:用于遍历可迭代对象的元素
- while 循环:用于在条件为真时重复执行代码
- do-while 循环:先执行一次循环体,然后再检查条件
此外,TypeScript 还提供了多种数组方法,如 forEach、map、filter、reduce 等,可以替代传统的循环结构,使代码更简洁、更易读。
通过合理使用这些循环结构和数组方法,你可以编写更清晰、更高效的 TypeScript 代码。