Skip to content

跳转语句(Day4 3/3) ​

本页对应 Day04_JavaScript,共 6 段视频,约 40 分钟。

学习目标 ​

  1. 能够使用 JavaScript 的 document.write() 结合 <table>、<tbody>、<tr>、<td> 输出页面表格,并验证九行九列及内容显示正确。
  2. 能够分析九九乘法表中行号、列号与单元格内容的关系,使用嵌套 for 循环实现正金字塔、倒金字塔等至少四种形式的九九乘法表。
  3. 能够使用 CSS 选择器(如 :not(:empty))为有内容的单元格设置边框和内边距,并隐藏无内容单元格的边框。
  4. 能够编写示例代码说明 continue 与 break 在循环中的区别,并验证 continue 跳过本次循环、break 结束整个循环的执行结果。
  5. 能够正确解释并演示省略大括号时,if、for、while 等结构只将相邻的一条语句视为其代码块,并能说明缩进不影响 JavaScript 的作用域判断。

知识点 ​

break:结束所在 case 或整个循环 ​

为什么需要:有些场景不是“把循环跑完”,而是条件满足后立刻停。比如 switch 中匹配到某个 case 后,不希望继续往下执行;循环中已经找到结果,也没必要继续迭代。break 就是用来“打断”的。

怎么想:先判断 break 处在什么结构里。在 switch case 中,它结束的是“所在的 case”,防止继续穿透到后面的 case;在循环中,它结束的是“整个循环”,一旦执行到 break,循环后面的迭代都不再发生。

怎么做:笔记里的核心规则是:

js
1. 在 switch case 中使用: 结束所在的 case
2. 在循环中使用: 结束循环,一旦执行到break,结束整个循环

转写稿里用 for 循环演示过:当 i 等于 5 时执行 break,console.log(i) 不再执行,并且整个循环结束。运行后看到的是 0 1 2 3 4,5 以及后面的 6、7、8、9、10 都没有输出。调试时先看输出停在哪里,再回到 if 条件,就能确认是 break 把整个循环结束了。

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

转写稿还提到一种常见用法:用 while (true) 写死循环,在循环里取随机数,当随机数满足条件时用 break 结束循环。这样不必把复杂条件全塞进 while 的循环条件里。

易错点:switch 里的 break 只结束当前 case,不是结束外层循环;循环里的 break 是结束整个循环,不要和 continue 混用。break 后面再写本次循环里的语句没有意义,因为执行不到。

continue:只跳过本次循环 ​

为什么需要:有时某一次循环的数据不需要处理,但后面的循环还要继续。比如遍历到 5 时想跳过 5,但 6、7、8 还要正常输出,这时不能用 break,而要用 continue。

怎么想:continue 的关键词是“本次”。执行到 continue 后,本次循环中它后面的语句不再执行,但循环不会整体结束,下一次循环继续。转写稿里的例子就是:i 等于 5 时 continue,于是 console.log(5) 被跳过,但 i 变成 6 后仍然继续输出。

怎么做:笔记里的规则是:

js
在循环中使用: 跳出本次循环,一旦执行到continue,本次循环中后面语句不再执行,下一次循环继续

对应代码:

js
for (var i = 0; i <= 10; i++) {
  if (i === 5) {
    continue;
  }
  console.log(i);
}
// 输出:0 1 2 3 4 6 7 8 9 10

转写稿的调试过程是:先运行,发现输出 0 1 2 3 4 6 7 8 9 10,少了 5;再检查 if (i === 5) 里执行了 continue,所以 console.log(5) 没有执行。注意在 for 循环里,continue 后仍会执行 i++,所以下一次循环能继续,不会卡在 5。

易错点:continue 只能用于循环中,不要拿去控制 switch;它只跳过本次,不是结束整个循环。若把 continue 误写成 break,输出会从 5 开始全部消失,这是两者最直观的区别。

对比与调试:看输出停在哪里 ​

为什么需要:break 和 continue 都叫“跳转”,但结果完全不同。对比着看,才能避免“想跳过一次却结束整个循环”。

怎么想:先问自己:我是要“这一次不做了”,还是“后面都不做了”?前者用 continue,后者用 break。

怎么做:用同一段循环分别替换关键字,观察输出。continue 版本输出 0 1 2 3 4 6 7 8 9 10;break 版本输出 0 1 2 3 4。转写稿里正是这样对比调试的:先看少了哪个数,再看循环有没有继续。

易错点:不要只看代码“像不像”,要运行看结果;break 和 continue 后面的语句都可能执行不到,写代码时不要把必要逻辑放在它们后面。

本节作业与课堂案例 ​

本节笔记中的作业如下,先保留原题:

1. 课堂案例 
2. 强化练习
    1. 使用 while 循环写四种形式的九九乘法表
    2. 输出100–200之间所有能被3或者7整除的数
    3. 输出三位数中,位上有3或者7的数字 100 ~ 999   
    4. 100 的阶乘 1*2*3....*100
    5. 求1!+2!+3!+...+20!的值

课堂转写主要围绕第1题展开:四种九九乘法表,以及 continue、break、省略大括号。下面按“为什么需要 → 怎么想 → 怎么做 → 易错点”整理。转写中演示多用 for,作业要求用 while,思路一致:把初始化、条件、更新拆开写即可。

四种九九乘法表:先搭表格骨架 ​

为什么需要:九九乘法表不是规则表格,第一行1个单元格,第二行2个……第九行9个。要先解决“行固定、列不固定”的结构问题。

怎么想:外层循环控制行,内层循环控制本行单元格个数。第一行1个、第二行2个,所以内层次数正好等于当前行号。表格仍用 table > tbody > tr > td 输出。

怎么做:先写样式,否则只输出标签页面看不见。关键样式包括 table-layout: fixed、border-collapse: collapse、td 的边框和内边距。第一种形式的核心循环:

js
document.write("<table><tbody>");
for (let i = 1; i <= 9; i++) {
  document.write("<tr>");
  for (let g = 1; g <= i; g++) {
    document.write("<td>" + g + "&times;" + i + "=" + (g * i) + "</td>");
  }
  document.write("</tr>");
}
document.write("</tbody></table>");

易错点:漏写 <td> 或 <tr>,页面结构不完整;document.write 拼成 right 会报错。转写中第32行就是把 write 拼错,控制台直接提示行号,改对后恢复。遇到结果不对,先看控制台报错,不要盲目逐行猜。

第二种:倒金字塔 ​

为什么需要:四种形式中第二种是倒序,第一行9个,最后一行1个。

怎么想:内层“第几行就输出几个”的规律不变,只改外层行号方向。

怎么做:外层从9到1,内层仍从1到当前 i:

js
for (let i = 9; i >= 1; i--) {
  document.write("<tr>");
  for (let g = 1; g <= i; g++) {
    document.write("<td>" + g + "&times;" + i + "=" + (g * i) + "</td>");
  }
  document.write("</tr>");
}

易错点:条件方向写反;忘记输出 tr 开始或结束标签。转写中第二种一开始漏写 td,只写内容不会形成单元格。

第三种:右对齐,用空白单元格“挤” ​

为什么需要:要让内容靠右,不能随便改单元格显示模式,比较稳的办法是每行仍放9个单元格,前面放空白格,后面放内容格。

怎么想:当前行有 i 个内容格,就需要 9 - i 个空白格。空白格在前,内容格在后,于是内容被挤到右边。

怎么做:一行里写两个并列循环:先输出 9 - i 个空 td,再输出 i 个有内容 td。样式只给非空单元格加边框:

css
td:not(:empty) {
  border: 1px solid #000;
  padding: 8px;
}

易错点:空 td 不能加可见边框,否则会露出空白格;两个循环是并列关系,变量都叫 g 不冲突,因为第一个循环已经结束。转写中强调:不要想当然,要分析作用域和执行顺序。

第四种:倒序加右对齐 ​

为什么需要:第四种是第三种的方向翻转。

怎么想:右对齐结构不变,只把外层 i 从9到1。

怎么做:空白格仍是 9 - i 个,内容格仍是 i 个,内容公式仍是 g × i = g*i。

易错点:漏掉 </tr> 会导致结构错乱;空白格循环和内容格循环要按“先空后内容”的顺序。

continue 与 break ​

为什么需要:循环中有时要跳过某次,有时要提前结束整个循环。

怎么想:continue 只跳过本次循环剩余语句,下一次继续;break 直接结束整个循环。二者都可用于 for、while、do while。

怎么做:

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

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

易错点:continue 不是结束整个循环;break 在 switch 中结束当前 case,在循环中结束整个循环。转写中还演示了“死循环 + break 取大于0.99随机数”的写法,说明同一需求可以多种写法,但初学要保证能退出。

省略大括号 ​

为什么需要:JS 允许分支和循环省略大括号,代码更短。

怎么想:省略后只认相邻的后一条语句为循环体或分支体,缩进不决定归属。

怎么做:

js
for (let i = 0; i < 10; i++)
  console.log("hello", i);

易错点:如果再写第二条语句,它不在循环体内;缩进也不会让它进入循环。if/else 同理。初学建议即使只有一句也写大括号,可读性更稳。

课堂画面 ​

课堂画面 1

课堂画面 2

课堂画面 3

课堂画面 4

课堂画面 5

课堂画面 6

代码示例 ​

示例 1:continue 与 break 对比 ​

html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>break 与 continue</title>
</head>
<body>
<script>
    // 1. continue:跳出本次循环,下一次循环继续
    for (var i = 0; i <= 10; i++) {
        if (i === 5) {
            continue;              // i 为 5 时,后面语句不再执行
        }
        console.log('continue: ' + i);   // 0 1 2 3 4 6 7 8 9 10
    }

    // 2. break:结束整个循环
    for (var i = 0; i <= 10; i++) {
        if (i === 5) {
            break;                 // i 为 5 时,整个循环直接结束
        }
        console.log('break: ' + i);      // 0 1 2 3 4
    }

    // 3. break 的常用套路:死循环 + 条件 break
    while (true) {
        var num = Math.random();
        if (num > 0.99) {
            console.log('取到大于 0.99 的随机数:' + num);
            break;                 // 条件满足才跳出死循环
        }
    }
</script>
</body>
</html>

要点解释

  • 关键行:if (i === 5) { continue; } —— 一旦执行到 continue,本次循环中它后面的 console.log 就不再执行,但下一次循环照常进行,所以输出里少了 5,6 7 8 9 10 全在。
  • 关键行:把 continue 换成 break,输出只有 0 1 2 3 4——break 不只是跳过后面语句,是把整个循环结束了。
  • 易错点:两者都只能用在循环(for、while、do while)里;break 还能用在 switch case 里,作用是结束所在 case,不写 break 会一直往下穿透。
  • 易错点:while (true) 是死循环,循环条件永远不会自己变假,必须靠 break 退出,否则页面直接卡死。
  • 易错点:判断条件用 === 全等,别写成 = 赋值。

示例 2:第一种形式九九乘法表(正金字塔,while/for 嵌套) ​

html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>第一种形式九九乘法表</title>
    <style>
        table {
            width: 900px;
            table-layout: fixed;
            border-collapse: collapse;
        }
        td {
            border: 1px solid #000;
            height: 60px;
            padding: 5px;
            text-align: center;
        }
    </style>
</head>
<body>
<script>
    document.write('<table><tbody>');
    for (var i = 1; i <= 9; i++) {          // 外层:控制 9 行
        document.write('<tr>');
        for (var g = 1; g <= i; g++) {      // 内层:第 i 行就循环 i 次
            document.write('<td>' + g + ' &times; ' + i + ' = ' + (g * i) + '</td>');
        }
        document.write('</tr>');
    }
    document.write('</tbody></table>');
</script>
</body>
</html>

要点解释

  • 关键行:for (var g = 1; g <= i; g++) —— 第 1 行 1 个单元格、第 2 行 2 个……行号 i 就是单元格个数,这就是不规则表格的规律。
  • 关键行:' &times; ' 用的是字符实体,因为内容要输出到文档流,和直接在 HTML 里写一样,直接敲 × 容易出乱码。
  • 关键行:(g * i) 必须加小括号——不加的话是字符串拼接,'1 * 2 = ' + 1 * 2 会先拼成 '1 * 2 = 1' 再乘,结果完全不对。括号的作用就是声明“这是一个整体,先算”。
  • 易错点:<table><tbody> 和结束标签必须自己 document.write 出来,不能只写单元格,否则浏览器会自动补全结构,表格直接乱掉。
  • 易错点:<td> 一定要写,只写内容不写 td 标签,表格里什么都看不见。
  • 易错点:内层循环变量不能也叫 i,会和外层冲突,所以换名 g;g <= i 是因为从 1 开始数,如果从 0 开始就要写 g < i。
  • 易错点:样式必须提前写好(border-collapse 合并边框、td 的边框和高度),否则标签写对了页面上也是一片空白。

示例 3:第三种形式九九乘法表(靠右金字塔 + :not(:empty) 隐藏空白格) ​

html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>第三种形式九九乘法表</title>
    <style>
        table {
            width: 900px;
            table-layout: fixed;
            border-collapse: collapse;
        }
        /* 只给有内容的单元格加边框和内边距,空白格就"消失"了 */
        td:not(:empty) {
            border: 1px solid #000;
            height: 60px;
            padding: 5px;
            text-align: center;
        }
    </style>
</head>
<body>
<script>
    document.write('<table><tbody>');
    for (var i = 1; i <= 9; i++) {
        document.write('<tr>');

        // 第一部分:空白单元格,个数是 9 - i
        for (var g = 1; g <= 9 - i; g++) {
            document.write('<td></td>');
        }

        // 第二部分:有内容的单元格,个数是 i
        for (var g = 1; g <= i; g++) {
            document.write('<td>' + g + ' &times; ' + i + ' = ' + (g * i) + '</td>');
        }

        document.write('</tr>');
    }
    document.write('</tbody></table>');
</script>
</body>
</html>

要点解释

  • 关键思路:每一行其实都是 9 个单元格,只是分成“空白”和“有内容”两组,空白组把有内容的格子挤到右边,形成靠右的塔形。
  • 关键行:for (var g = 1; g <= 9 - i; g++) —— 当 i = 1 时是 8 个空白,i = 9 时是 0 个空白,最后一行刚好没有空白。
  • 关键行:td:not(:empty) —— :empty 表示既没有内容也没有子元素,not() 把它排除掉,于是只有带内容的格子有边框,空白格看不见。
  • 易错点:两个内层循环是并列执行的,前一个循环已经结束了,所以标记变量都叫 g 不冲突;但如果是嵌套循环,就绝对不能重名。
  • 易错点:空白格必须写成 <td></td>,中间不能有任何空格或换行,否则 :empty 就不成立,空白格子会带边框显示出来。
  • 易错点:写完发现页面全空,先按 F12 看控制台报错,按提示找到出错行号,比一行行猜快得多(本节就踩过 write 拼错的坑)。
  • 拓展:第四种形式只需把外层 for (var i = 1; i <= 9; i++) 改成 for (var i = 9; i >= 1; i--),内层代码一个字都不用动,就是倒金字塔。

常见错误 ​

  1. 内层循环误用外层变量名 现象:乘法表每行单元格数全一样,或直接死循环。 原因:内层 for 又声明了 i,覆盖了外层行号,j <= i 的条件永远成立。 修法:内层一律换名(j/k),并在写循环前先列出"外层管什么、内层管什么"。

  2. 只写内容不写 <td> 现象:页面一片空白,但检查元素能看到 tbody 和 tr。 原因:document.write 拼出的纯文本/字符实体直接落在 <tr> 里,浏览器按表格模型丢弃。 修法:任何要显示的内容必须包在 <td>...</td> 中;拼字符串时先写骨架 <td></td>,再往里塞内容。

  3. write 拼写错误导致后续全丢 现象:表格只剩一个 <tr>,或整段输出戛然而止,无任何视觉提示。 原因:documet.right 之类笔误抛 ReferenceError,脚本中断,后面的 write 不再执行。 修法:结果不对先按 F12 看 Console 报错行号,按提示定位;不要靠肉眼逐行扫代码。

  4. break 与 continue 用反 现象:想跳过 5,结果 5 之后的 6~10 全没了;或想终止循环却只少了一次。 原因:把"结束整个循环"和"结束本次循环"混为一谈。 修法:判断标准——后续还要不要继续迭代?要 → continue;不要 → break。写完先用 1~10 的小循环验证一次。

  5. 省略大括号后多写了一行 现象:第二条 console.log 只输出一次,缩进看起来却像在循环里。 原因:省略 {} 时只有紧邻的一条语句属于循环体/分支体,缩进不参与语法判定。 修法:只要循环体/分支体超过一条语句就必须补 {};建议即便只有一条也保留大括号。

  6. 用 :empty 隐藏空白单元格失效 现象:第三种乘法表左侧空白格仍有边框,表格宽度被撑满。 原因:<td> </td> 或 <td>\n</td> 中含空白字符,不满足 :empty 的"完全无内容"条件。 修法:空白 td 写成 <td></td> 不留任何字符;或改用类名 .blank 精确控制样式,不依赖 :empty。

  7. 大数阶乘结果末位错乱 现象:100! 输出成一串科学计数法,1!+...+20! 求和后个位与手算不符。 原因:超出 Number.MAX_SAFE_INTEGER 后双精度浮点丢失低位精度。 修法:需要精确值用 BigInt(1n、*=、+),或只做字符串/数组模拟进位。

练习 ​

  1. 用 while 重写第一种九九乘法表(禁止使用 for),写完后回答:内层循环条件写成 j <= i 与 j < i 分别会得到什么图形?
  2. 用死循环 + break 实现:不断生成 Math.random(),直到取到大于 0.99 的数为止,输出尝试次数。再用 while 条件写法实现一遍,比较两种写法各自的适用场景。
  3. 输出 100~200 之间所有能被 3 或 7 整除的数。要求分别用 continue 过滤版和 if 直接判断版各写一次,并说明两版可读性差异。
  4. 把第三种(右对齐)乘法表改造为:空白格不加任何 CSS 类,有内容格加 class="cell",样式全部写在 .cell 上。改完后对比 :empty 方案,说明哪种更不容易被后续改动破坏。
  5. 下面代码输出什么?先手写答案再运行验证,然后改成你认可的写法:
    js
    for (let i = 0; i < 3; i++)
        console.log('A' + i);
        console.log('B' + i);
  6. 求 1! + 2! + ... + 20!,先用普通 Number 算,再用 BigInt 算,对比两者末几位数字,说明差异来源。

原视频对照 ​

#视频时长
1第一种形式九九乘法表09:48
2第二种形式九九乘法表04:55
3第三种形式九九乘法表08:21
4第四种形式九九乘法表05:47
5continue和break07:08
6省略大括号04:38

小结 ​

  1. 图形类输出(乘法表、金字塔)的通用切入点是:先数清"行数由谁控制、每行列数由谁控制",把两者映射到循环变量上,图形自然浮现。
  2. 四种乘法表之间真正变化的只有两处——外层循环方向和空白格数量(9 - i),内层内容逻辑几乎零改动。能识别"哪里不变"比能写出代码更有价值。
  3. 排版类需求优先考虑"结构占位 + 样式隐藏",而不是在 JS 里做视觉判断;把"生成"和"呈现"分开,代码会短很多。
  4. break 的典型场景是"次数不确定、达成即止",continue 的典型场景是"遍历全部、过滤部分",选错会让循环语义与意图背离。
  5. 结果异常时的排查顺序固定为:控制台报错 → 检查元素看 DOM 结构 → 打印中间变量,不要一上来就通读代码。
  6. 省略大括号属于风格选项而非语法能力,个人偏好应让位于团队规范;缩进在 JS 里只是给人看的,不构成作用域。
  7. 涉及阶乘、累加等数值膨胀的场景,先估算量级再选数据类型,浮点精度问题一旦发生无法靠"多算几次"弥补。