循环控制 #

一、循环控制概述 #

循环控制语句用于改变循环的正常执行流程。Deno提供了break、continue和标签语句来控制循环。

二、break语句 #

2.1 基本用法 #

break语句用于立即退出循环:

typescript
for (let i = 0; i < 10; i++) {
  if (i === 5) {
    break;
  }
  console.log(i);
}
// 输出:0 1 2 3 4

2.2 在while中使用 #

typescript
let count = 0;

while (true) {
  console.log(count);
  count++;
  
  if (count >= 5) {
    break;
  }
}
// 输出:0 1 2 3 4

2.3 查找元素 #

typescript
const numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
let found: number | undefined;

for (const num of numbers) {
  if (num > 5) {
    found = num;
    break;
  }
}

console.log(found); // 6

2.4 验证数据 #

typescript
function hasInvalidNumber(numbers: number[]): boolean {
  for (const num of numbers) {
    if (num < 0 || num > 100) {
      return true;
    }
  }
  return false;
}

console.log(hasInvalidNumber([1, 2, 3])); // false
console.log(hasInvalidNumber([1, -1, 3])); // true

三、continue语句 #

3.1 基本用法 #

continue语句用于跳过当前迭代,继续下一次迭代:

typescript
for (let i = 0; i < 5; i++) {
  if (i === 2) {
    continue;
  }
  console.log(i);
}
// 输出:0 1 3 4

3.2 过滤数据 #

typescript
const numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];

console.log("奇数:");
for (const num of numbers) {
  if (num % 2 === 0) {
    continue;
  }
  console.log(num);
}
// 输出:1 3 5 7 9

3.3 跳过无效数据 #

typescript
const data = [
  { id: 1, name: "Alice" },
  { id: 2, name: "" },
  { id: 3, name: "Charlie" },
  null,
  { id: 4, name: "Diana" }
];

for (const item of data) {
  if (!item || !item.name) {
    continue;
  }
  console.log(`${item.id}: ${item.name}`);
}
// 输出:1: Alice 3: Charlie 4: Diana

3.4 处理文件行 #

typescript
const lines = [
  "# 注释行",
  "",
  "hello world",
  "  ",
  "foo bar",
  "# 另一个注释"
];

for (const line of lines) {
  const trimmed = line.trim();
  
  if (!trimmed || trimmed.startsWith("#")) {
    continue;
  }
  
  console.log(trimmed);
}
// 输出:hello world foo bar

四、标签语句 #

4.1 基本语法 #

typescript
labelName: {
  // 代码块
}

labelName: for (...) {
  // 循环
}

4.2 跳出嵌套循环 #

typescript
outer: for (let i = 0; i < 3; i++) {
  for (let j = 0; j < 3; j++) {
    if (i === 1 && j === 1) {
      break outer;
    }
    console.log(`i: ${i}, j: ${j}`);
  }
}
// 输出:i: 0, j: 0  i: 0, j: 1  i: 0, j: 2  i: 1, j: 0

4.3 继续外层循环 #

typescript
outer: for (let i = 0; i < 3; i++) {
  for (let j = 0; j < 3; j++) {
    if (j === 1) {
      continue outer;
    }
    console.log(`i: ${i}, j: ${j}`);
  }
}
// 输出:i: 0, j: 0  i: 1, j: 0  i: 2, j: 0

4.4 查找二维数组 #

typescript
const matrix = [
  [1, 2, 3],
  [4, 5, 6],
  [7, 8, 9]
];

function findInMatrix(matrix: number[][], target: number): [number, number] | null {
  let result: [number, number] | null = null;
  
  search: for (let i = 0; i < matrix.length; i++) {
    for (let j = 0; j < matrix[i].length; j++) {
      if (matrix[i][j] === target) {
        result = [i, j];
        break search;
      }
    }
  }
  
  return result;
}

console.log(findInMatrix(matrix, 5)); // [1, 1]

4.5 标签代码块 #

typescript
function processData(data: string): string | null {
  let result: string | null = null;
  
  process: {
    if (!data) {
      break process;
    }
    
    const trimmed = data.trim();
    if (!trimmed) {
      break process;
    }
    
    result = trimmed.toUpperCase();
  }
  
  return result;
}

console.log(processData("  hello  ")); // "HELLO"
console.log(processData("")); // null

五、return替代break #

5.1 在函数中使用return #

typescript
function findFirst<T>(arr: T[], predicate: (item: T) => boolean): T | undefined {
  for (const item of arr) {
    if (predicate(item)) {
      return item;
    }
  }
  return undefined;
}

const numbers = [1, 2, 3, 4, 5];
const firstEven = findFirst(numbers, n => n % 2 === 0);
console.log(firstEven); // 2

5.2 提前退出 #

typescript
function processArray(arr: number[]): number {
  if (arr.length === 0) {
    return 0;
  }
  
  let sum = 0;
  for (const num of arr) {
    if (num < 0) {
      return -1;
    }
    sum += num;
  }
  
  return sum;
}

六、实际应用 #

6.1 表单验证 #

typescript
interface FormData {
  username: string;
  email: string;
  password: string;
}

function validateForm(data: FormData): { valid: boolean; error?: string } {
  const fields: Array<{ key: keyof FormData; value: string; rules: Array<(v: string) => string | null> }> = [
    {
      key: "username",
      value: data.username,
      rules: [
        v => v.length < 3 ? "用户名至少3个字符" : null,
        v => !/^[a-zA-Z0-9_]+$/.test(v) ? "用户名只能包含字母、数字和下划线" : null
      ]
    },
    {
      key: "email",
      value: data.email,
      rules: [
        v => !v.includes("@") ? "邮箱格式不正确" : null
      ]
    },
    {
      key: "password",
      value: data.password,
      rules: [
        v => v.length < 8 ? "密码至少8个字符" : null
      ]
    }
  ];
  
  for (const field of fields) {
    for (const rule of field.rules) {
      const error = rule(field.value);
      if (error) {
        return { valid: false, error: `${field.key}: ${error}` };
      }
    }
  }
  
  return { valid: true };
}

6.2 分批处理 #

typescript
async function processInBatches<T>(
  items: T[],
  batchSize: number,
  processor: (batch: T[]) => Promise<void>
): Promise<void> {
  for (let i = 0; i < items.length; i += batchSize) {
    const batch = items.slice(i, i + batchSize);
    await processor(batch);
  }
}

6.3 带超时的轮询 #

typescript
async function pollWithTimeout(
  checkFn: () => Promise<boolean>,
  options: { interval?: number; timeout?: number } = {}
): Promise<boolean> {
  const { interval = 1000, timeout = 30000 } = options;
  const startTime = Date.now();
  
  while (true) {
    if (await checkFn()) {
      return true;
    }
    
    if (Date.now() - startTime >= timeout) {
      return false;
    }
    
    await new Promise(resolve => setTimeout(resolve, interval));
  }
}

6.4 游戏循环 #

typescript
interface GameState {
  running: boolean;
  score: number;
}

async function gameLoop(state: GameState): Promise<void> {
  while (state.running) {
    // 更新游戏状态
    state.score++;
    
    // 渲染
    console.log(`Score: ${state.score}`);
    
    // 延迟
    await new Promise(resolve => setTimeout(resolve, 100));
    
    // 检查结束条件
    if (state.score >= 10) {
      state.running = false;
    }
  }
  
  console.log("Game Over!");
}

七、最佳实践 #

7.1 避免深层嵌套 #

typescript
// 不推荐
for (const a of arrA) {
  for (const b of arrB) {
    for (const c of arrC) {
      if (condition) {
        // 处理
      }
    }
  }
}

// 推荐:使用提前退出或提取函数
function processItem(a: TypeA, b: TypeB, c: TypeC): boolean {
  if (!condition) {
    return false;
  }
  // 处理
  return true;
}

7.2 使用数组方法 #

typescript
// 使用循环
const result: number[] = [];
for (const num of numbers) {
  if (num > 5) {
    result.push(num * 2);
  }
}

// 使用数组方法
const result2 = numbers
  .filter(num => num > 5)
  .map(num => num * 2);

7.3 避免无限循环 #

typescript
// 危险:可能无限循环
while (true) {
  // 忘记break条件
}

// 安全:设置最大迭代次数
let iterations = 0;
const maxIterations = 1000;

while (condition && iterations < maxIterations) {
  // 处理
  iterations++;
}

八、总结 #

本章学习了:

  • break语句退出循环
  • continue语句跳过迭代
  • 标签语句控制嵌套循环
  • return替代break
  • 实际应用场景
  • 最佳实践

下一章,我们将学习函数。

最后更新:2026-03-28