Skip to content

1-16对象综合案例 ​

本页对应 第一章JavaScript基础,共 7 段视频,约 1 小时 3 分。

学习目标 ​

  • 能使用 Math.random() 与 Math.floor() 生成指定范围的随机整数,并将其作为数组索引随机抽取数组元素。
  • 能使用 while 循环、if...else 分支和 break 实现猜数字游戏,并在猜对后正确退出循环。
  • 能使用 for 循环限定猜数字次数,通过开关变量控制次数用完提示,并说明 flag 赋值需写在 break 之前的执行逻辑。
  • 能封装带布尔参数和默认参数的颜色函数,根据参数返回不同格式的随机颜色。
  • 能分别生成随机 RGB 颜色和十六进制颜色,包括生成 3 个 0–255 随机数、循环 6 次随机取字符并拼接字符串。
  • 能根据对象数组使用循环和模板字符串拼接标签,并将渲染结果写入指定容器完成学成在线页面渲染。

知识点 ​

案例目标与效果 ​

学成在线精品推荐模块效果图

本节做一个“学成在线”精品推荐模块的综合案例:根据对象数组数据渲染列表页面。页面里每个课程卡片结构相同,只有图片、标题、学习人数不同。如果继续手写 10 个 li,代码重复、后期改数据也麻烦。所以核心思路是:准备对象数组 → 用循环拼接字符串生成多个 li → 把生成的字符串放入 ul 容器中渲染。这和之前做学生信息表渲染每一行的思路相似,只是这次渲染的是真正的 li 标签。

数据准备:对象数组 ​

为什么需要数据?因为页面中变化的只有 src、title、num 三个位置,其余结构一致。怎么想?把每个课程卡片抽象成一个对象,多个卡片就是对象数组。怎么做?声明 let data = [...],每个对象包含图片地址、标题、学习人数。易错点:字段名要统一,后面模板字符串里要用 data[i].src、data[i].title、data[i].num,写错一个字母就取不到值。

循环拼接字符串 ​

为什么需要循环?因为数组里有多个对象,要生成多个结构相同的 li。怎么想?先在循环外准备一个空字符串 let str = '',再 for 循环遍历数组,每次把一段 li 结构拼到 str 后面。怎么做?用模板字符串拼接,变量位置写成 \${data[i].src} 等。转写稿中的调试过程是:先 console.log(str) 看是否生成了多个 li,确认结构没问题后,再逐个把写死的图片、标题、人数替换成数据。易错点:str 必须声明在循环外;for 循环条件用 i < data.length;img 的 src 属性外面仍要保留双引号,变量写在双引号里面,如 src="\${data[i].src}"。

渲染到页面 ​

为什么还要渲染?因为拼接好的 str 只是字符串,还没有进入页面。怎么想?最终容器是 ul.common,把 \${str} 放进 ul 内部,再用 document.write() 输出整体结构。怎么做?先输出外层 div.course.wrapper、标题区 .hd、内容区 .bd,在 <ul class="common"> 中写入 \${str}。易错点:模板字符串里再嵌套模板字符串时要分清 \${};ul 的类名不要写错;如果页面有小图标错误,检查 iconfont 相关 CSS 是否引入。转写稿中还验证了:在数据里多加一条,页面就会多一个卡片,说明页面由数据驱动。

完整代码 ​

html
<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>学成在线</title>
  <link rel="stylesheet" href="./iconfont/iconfont.css">
  <link rel="stylesheet" href="./css/base.css">
  <link rel="stylesheet" href="./css/index.css">
</head>

<body>

  <!-- 精品课程 -->
  <script>
    // 综合案例代码
    // 1. 利用对象数组的数据渲染页面
    // 综合案例代码
    let data = [
      {
        src: './uploads/quality01.png',
        title: 'JavaScript数据看板项目实战',
        num: 1125
      },
      {
        src: './uploads/quality02.png',
        title: 'Vue.js实战——面经全端项目',
        num: 2726
      },
      {
        src: './uploads/quality03.png',
        title: '玩转Vue全家桶,iHRM人力资源项目',
        num: 9456
      },
      {
        src: './uploads/quality04.png',
        title: 'Vue.js实战医疗项目——优医问诊',
        num: 7192
      },
      {
        src: './uploads/quality05.png',
        title: '小程序实战:小兔鲜电商小程序项目',
        num: 2703
      },
      {
        src: './uploads/quality06.png',
        title: '前端框架Flutter开发实战',
        num: 2841
      },
      {
        src: './uploads/quality07.png',
        title: '熟练使用React.js——极客园H5项目',
        num: 95682
      },
      {
        src: './uploads/quality08.png',
        title: '熟练使用React.js——极客园PC端项目',
        num: 904
      },
      {
        src: './uploads/quality09.png',
        title: '前端实用技术,Fetch API 实战',
        num: 1516
      },
      {
        src: './uploads/quality10.png',
        title: '前端高级Node.js零基础入门教程',
        num: 2766
      },
      {
        src: './uploads/quality10.png',
        title: '前端高级Node.js零基础入门教程',
        num: 27669
      }
    ]
    // 2. 利用循环来做字符串拼接生成多个li标签,之后把生成的li标签放入容器 ul 里面渲染即可
    let str = ''
    for (let i = 0; i < data.length; i++) {
      // console.log(data[i]) // 每个对象
      str += `
`<li>`
          <a href="#">
            <div class="pic">
              <img src="\${data[i].src}" alt="">
            </div>
            <h4>\${data[i].title}</h4>
            <p><span>高级</span> · <i>\${data[i].num}</i>人在学习</p>
          </a>
        </li>
      `
    }
    console.log(str)

    document.write(`
      <div class="course wrapper">
        <div class="hd">
          <h3>精品推荐</h3>
          <a href="#">查看全部
            <span class="iconfont icon-arrow-right-bold">
            </span>
          </a>
        </div>
        <div class="bd">
          <ul class="common">
            \${str}
          </ul>
        </div>
      </div>
    `)

  </script>
</body>

</html>

调试与易错点小结 ​

调试时先打印 str,确认循环是否生成了正确数量的 li;再检查 src、title、num 是否被替换成数据;最后把 \${str} 放进 ul 中输出。易错点:空字符串要在循环前声明;模板字符串变量必须用 \${};img 的 src 属性双引号不要丢;CSS 资源路径要正确;新增数据后页面能自动多出卡片,说明数据驱动渲染成功。

一、栈与堆:基本类型和引用类型分别存哪里 ​

为什么需要: 变量不只是“起个名字”,它还要在内存中占位置。先分清栈和堆,才能理解为什么基本类型访问快、引用类型容量大,也才能看懂后面数组、对象、函数参数为什么能传来传去。

怎么想: 笔记给出的结论很明确:栈访问速度快,基本数据类型存放到栈里面;堆存储容量大,引用数据类型存放到堆里面。 可以把栈想成手边的小抽屉,取用快;堆想成大仓库,能放更多东西。数组、对象这类引用类型的数据本体在堆中,我们通过引用去访问它。

怎么做: 对照下面两张图理解内存分配:

栈与堆存储基本类型和引用类型示意图

基本数据类型与引用数据类型在内存中的分配示意图

易错点: 不要把“变量名”和“数据本体”混为一谈;也不要把所有数据都认为存在栈里。基本类型直接存值,引用类型重点在“引用/地址”与堆中数据的关系。

二、变量声明:const 优先,必要时再改 let ​

为什么需要: 很多变量声明后根本不会再改。如果一开始就用 let,后面可能被误改,安全性差。笔记明确建议:const 优先,尽量使用 const。实际开发中,比如 React、Vue,基本用 const 声明。

怎么想: 总结成一句话:有了变量先给 const,如果发现它后面是要被修改的,再改为 let。 先判断“这个值以后会不会重新赋值”,不会就 const,会就 let。

怎么做: 例如转写稿的猜数字限定次数案例中,开关变量 flag 一开始是 true,猜对后要改成 false,所以它必须用 let;而某些只读取、不再改的配置值,就适合 const。写代码时先写 const,报错或发现要重新赋值时再改 let。

易错点: 不要因为习惯先写 let;也不要把后面明确要修改的变量硬写成 const。判断标准不是“值长不长”,而是“后面是否重新赋值”。

三、专业术语:读懂文档、报错和代码 ​

为什么需要: 关键字、保留字、标识符、表达式、语句这些词会出现在文档、报错和面试题里。分不清它们,就看不懂“这里要写表达式”“这是语句”等说明。

怎么想: 关键字是 JavaScript 中有特殊意义的词汇;保留字是目前没意义、未来可能有特殊意义的词汇;标识(标识符)是变量名、函数名的另一种叫法;表达式可以被求值,一般配合运算符出现;语句是一段可执行代码。

怎么做: 保留笔记中的术语表:

术语解释举例
关键字在JavaScript中有特殊意义的词汇let、var、function、if、else、switch、case、break
保留字在目前的JavaScript中没意义,但未来可能会具有特殊意义的词汇int、short、long、char
标识(标识符)变量名、函数名的另一种叫法无
表达式可以被求值的代码,一般配合运算符出现10 + 3、age >= 18
语句一段可执行的代码if ()、for()

易错点: 10 + 3 是表达式,if () {} 是语句;不要把“关键字”和“保留字”混用;变量名不能随便用关键字。

四、把数据存储落到案例:随机索引、循环与函数参数 ​

为什么需要: 只背“栈、堆、const”不够,案例能检验我们是否真的会用变量存数据、用索引取数据、用循环处理一批数据。

怎么想: 转写稿里的“随机显示姓名”核心是:先生成数组索引号,再用 数组[索引] 取元素。转写稿里的“缩引号”应纠正为“索引号”。索引范围是 0 到 arr.length - 1,所以公式是:

js
let index = Math.floor(Math.random() * arr.length);
document.write(arr[index]);

调试时先打印随机数,确认最小是 0、最大不超过 arr.length - 1,再取数组元素。猜数字案例则先随机生成 1 到 10 的整数,再用 while (true) 不断让用户输入;用户输入用 prompt 得到的是字符串,比较前要转成数字。限定三次时,把无限循环改成 for (let i = 1; i <= 3; i++),并用 flag 控制“次数用完”的提示:

js
let flag = true;
for (let i = 1; i <= 3; i++) {
  let num = +prompt('请输入1到10之间的整数');
  if (num === random) {
    alert('恭喜你猜对了');
    flag = false;
    break;
  } else if (num > random) {
    alert('数字猜大了,继续猜');
  } else {
    alert('数字猜小了,继续猜');
  }
}
if (flag) alert('你的次数已经用完了');

随机颜色案例中,函数参数 flag = true 用默认值控制返回十六进制还是 RGB;RGB 要生成三个独立的 0 到 255 随机整数,不能共用一个;十六进制则准备包含 0 到 F 的数组,循环 6 次,用随机索引取字符并拼接到 # 后面。学成在线渲染则是对象数组配合 for 循环拼接 li 字符串,再放入 ul 容器。

易错点: 随机索引不要写成 Math.random() * (arr.length - 1);prompt 输入要转数字;猜对时 flag = false 要写在 break 前面,否则可能误弹“次数用完”;十六进制要循环 6 次,RGB 要生成三个不同随机数;拼接 src 时双引号要保留在字符串里。

课件图示 ​

课件第4页:对象-Object 对象(Object):JavaScript里的一种数据类型(

课件第12页:1.2 操作对象 l 对象本质是无序的数据集合, 操作对象数据无非就是 增 删

课件第22页:案例 遍历对象数组 需求:请把下面所有数据中的家乡打印出来: // 定义一个存储

课件第23页:案例 渲染表格案例 需求:根据以上数据渲染生成表格

课件第24页:案例 渲染表格案例 需求:根据以上数据渲染生成表格 分析: ①:中间的行根据数据

课件第39页:案例 学成在线页面渲染案例 需求:根据数据渲染列表页面

课件第42页:JS 数据类型整体分为两大类: Ø 基本数据类型(简单数据类型) Ø 引用数据类

课件第44页:内存中堆栈空间分配区别: l 栈: 优点访问速度快,基本数据类型存放到栈里面 l

代码示例 ​

示例一:综合案例——根据对象数组渲染精品推荐列表(学成在线)

js
<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>学成在线</title>
  <link rel="stylesheet" href="./iconfont/iconfont.css">
  <link rel="stylesheet" href="./css/base.css">
  <link rel="stylesheet" href="./css/index.css">
</head>

<body>

  <!-- 精品课程 -->
  <script>
    // 1. 利用对象数组的数据渲染页面
    let data = [
      {
        src: './uploads/quality01.png',
        title: 'JavaScript数据看板项目实战',
        num: 1125
      },
      {
        src: './uploads/quality02.png',
        title: 'Vue.js实战——面经全端项目',
        num: 2726
      },
      {
        src: './uploads/quality03.png',
        title: '玩转Vue全家桶,iHRM人力资源项目',
        num: 9456
      },
      {
        src: './uploads/quality04.png',
        title: 'Vue.js实战医疗项目——优医问诊',
        num: 7192
      },
      {
        src: './uploads/quality05.png',
        title: '小程序实战:小兔鲜电商小程序项目',
        num: 2703
      },
      {
        src: './uploads/quality06.png',
        title: '前端框架Flutter开发实战',
        num: 2841
      },
      {
        src: './uploads/quality07.png',
        title: '熟练使用React.js——极客园H5项目',
        num: 95682
      },
      {
        src: './uploads/quality08.png',
        title: '熟练使用React.js——极客园PC端项目',
        num: 904
      },
      {
        src: './uploads/quality09.png',
        title: '前端实用技术,Fetch API 实战',
        num: 1516
      },
      {
        src: './uploads/quality10.png',
        title: '前端高级Node.js零基础入门教程',
        num: 2766
      },
      {
        src: './uploads/quality10.png',
        title: '前端高级Node.js零基础入门教程',
        num: 27669
      }
    ]

    // 2. 利用循环来做字符串拼接生成多个 li 标签,之后把生成的 li 标签放入容器 ul 里面渲染即可
    let str = ''
    for (let i = 0; i < data.length; i++) {
      // console.log(data[i]) // 每个对象
      str += `
         <li>
          <a href="#">
            <div class="pic">
              <img src="${data[i].src}" alt="">
            </div>
            <h4>${data[i].title}</h4>
            <p><span>高级</span> · <i>${data[i].num}</i>人在学习</p>
          </a>
        </li>
      `
    }
    console.log(str)

    // 3. 把拼好的 li 字符串放进 ul 容器,整体输出到页面
    document.write(`
      <div class="course wrapper">
        <div class="hd">
          <h3>精品推荐</h3>
          <a href="#">查看全部
            <span class="iconfont icon-arrow-right-bold">
            </span>
          </a>
        </div>
        <div class="bd">
          <ul class="common">
            ${str}
          </ul>
        </div>
      </div>
    `)

  </script>
</body>

</html>

要点解释 / 易错点:

  • data 是对象数组,数组里每个对象对应页面上的一个 li,页面结构只写一份,靠循环批量生成,数据变了页面自动变。
  • let str = '' 必须写在 for 循环外面。写在循环里面每次循环都会被重置成空串,最后只剩最后一个 li。
  • 用模板字符串(反引号)配合 \${} 取值:\${data[i].src}、\${data[i].title}、\${data[i].num},正好对应三个会变的地方(图片地址、标题、学习人数)。
  • src 比较特殊:外面的双引号要正常写,把 \${data[i].src} 放进双引号里,写成 src="\${data[i].src}",不要因为字符串本身带引号就省掉属性引号。
  • 循环条件用 i < data.length,不要写成 <=,否则 data[data.length] 是 undefined,会多渲染一个空 li。
  • 最后 document.write() 里用 \${str} 把拼好的所有 li 塞进 <ul class="common"> 容器中,一次性渲染。
  • 字符串拼接要严谨,不要随意多敲空格(如 src=" ..."),浏览器可能容错,但代码不规范。

示例二:封装随机颜色函数(十六进制 / rgb 双格式)

js
<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <title>随机颜色</title>
</head>

<body>
  <script>
    // 不传参 / 传 true → 返回十六进制;传 false → 返回 rgb 格式
    function getRandomColor(flag = true) {
      if (flag) {
        // 十六进制:# 开头 + 6 位 0~f 的字符
        let arr = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f']
        let str = '#'
        for (let i = 1; i <= 6; i++) {
          let random = Math.floor(Math.random() * 16) // 0 ~ 15,正好是数组索引
          str += arr[random]
        }
        return str
      } else {
        // rgb 格式:需要三个独立的 0~255 随机整数
        let r = Math.floor(Math.random() * 256)
        let g = Math.floor(Math.random() * 256)
        let b = Math.floor(Math.random() * 256)
        return `rgb(${r},${g},${b})`
      }
    }

    console.log(getRandomColor())       // 不传参 → 十六进制
    console.log(getRandomColor(true))   // 传 true → 十六进制
    console.log(getRandomColor(false))  // 传 false → rgb
  </script>
</body>

</html>

要点解释 / 易错点:

  • 形参默认值 flag = true:不传实参时形参就是 true,自动走十六进制分支,省去了判空。
  • 十六进制里含 a~f 字符,Math.random() 生成不了字符,所以要先准备一个 16 个字符的数组,用随机索引去取值。
  • Math.floor(Math.random() * 16) 得到 0~15,正好是数组的索引范围,取出来就是一位十六进制字符。
  • str = '#' 要声明在循环外面,循环 6 次每次 str += arr[random],拼完 6 位再 return str。
  • rgb 必须生成三个独立的随机数,不能共用一个变量,否则红绿蓝三值相同,颜色就固定了。
  • 0~255 要乘 256(最大值 + 1),不是乘 255,否则取不到 255。
  • if 分支里 return 一旦执行函数就结束了,两个 return 不会冲突。

示例三:从数组中随机抽取一个元素(随机显示姓名)

html
<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <title>随机显示姓名</title>
</head>

<body>
  <script>
    // 五虎上将
    let arr = ['关羽', '张飞', '赵云', '马超', '黄忠']

    // 随机生成 0 ~ arr.length - 1 的整数,作为数组索引
    let index = Math.floor(Math.random() * arr.length)
    console.log(index)

    // 用索引取出元素,显示到页面
    document.write(arr[index])
  </script>
</body>

</html>

要点解释 / 易错点:

  • 抽元素的核心是先拿到合法的索引号,再用 arr[index] 取值。
  • 通用公式:Math.floor(Math.random() * arr.length),因为数组索引从 0 开始,到 length - 1 结束,正好用数组长度来乘,数组内容变了也不用改公式。
  • 必须 Math.floor 取整,Math.random() 本身是小数,直接当索引会得到 undefined。
  • 不要写成 Math.random() * arr.length - 1 或漏掉 floor,那会越界或少取到最大值。
  • document.write() 只适合这种练习页面,会直接往文档里写内容。

常见错误 ​

1. 列表只渲染出最后一个 li

  • 现象:页面上只有一条数据,或者 str 打印出来只有一小段。
  • 原因:字符串变量声明在循环体内(每轮被重置),或者写成 str = ... 覆盖而不是 str += ...。
  • 修法:let str = '' 必须在循环之前声明;循环体内只用 += 追加。判断技巧——变量"跨轮次累积"就一定要提到循环外面。

2. img 的 src 拼出来没有引号或多了空格

  • 现象:图片不显示;或控制台 Elements 里 src 值被浏览器"修正"成奇怪的东西。
  • 原因:模板字符串里写成 src=\${data[i].src},属性值裸露;或 src = "..." 手滑多敲空格。
  • 修法:属性值永远写全 src="\${data[i].src}";拼完后用 Elements 面板核对一次真实 DOM,不要只看页面"看起来对"。

3. 猜数字里"猜对了却一直让猜"或"猜对后仍弹出次数用完"

  • 现象:输入正确值后弹窗继续;或者同时弹出"恭喜"和"次数已用完"。
  • 原因:break 漏写;或开关变量 flag = false 写在了 break 的下面(break 之后的语句不再执行)。
  • 修法:顺序固定为「先改开关 → 再 break」,且 break 只负责跳出循环、不负责通知外部,两者缺一不可。

4. prompt 的返回值直接和数字比较

  • 现象:输入正确数字却提示"猜大了/猜小了",或比较结果诡异。
  • 原因:prompt 返回字符串,'5' > 10 这类隐式转换与 '5' === 5 都为假,混用 ==/=== 时行为不一致。
  • 修法:入口处立刻 let num = +prompt(...) 或 Number(...) 转成数字,再进入比较逻辑;转换只做一次,别在分支里反复转。

5. 随机取数组元素取到 undefined

  • 现象:偶尔渲染出 undefined,或抽名字时页面空白。
  • 原因:区间公式少 +1,Math.floor(Math.random() * arr.length) 本身是对的,但手改成 * (max - min) 或 * 10 时漏掉最大值,导致下标越界或永远取不到最后一项。
  • 修法:统一记成 Math.floor(Math.random() * (max - min + 1)) + min;取数组元素时直接 * arr.length,不要自己数长度。

6. 封装 getRandomColor 后不传参返回了 RGB

  • 现象:getRandomColor() 期望十六进制,实际拿到 rgb(...)。
  • 原因:形参没给默认值,flag 是 undefined,if (flag) 判假直接进 else。
  • 修法:function getRandomColor(flag = true);并且判断写成显式的 if (flag) / else,不要依赖"空值恰好等于 false"。

7. 十六进制颜色只拼出最后一位

  • 现象:返回 #f 这种一位颜色,或 # 后只有一个字符。
  • 原因:let str = '#' 写在了 for 循环里面,每次循环都被重置。
  • 修法:累加型字符串一律在循环外初始化;同时确认循环次数是 6 次而不是数组长度 16 次。

8. 用 document.write 渲染,页面只剩列表

  • 现象:点击某个按钮后再渲染,整个页面被冲掉,样式和其他模块全没了。
  • 原因:document.write 在文档流关闭后调用会重写整个文档。
  • 修法:真实项目一律用 容器.innerHTML = str;document.write 只用于教学演示的一次性写入。

练习 ​

练习 1|两种拼接方式对比 用 for 循环和 map().join('') 各写一遍学成在线列表渲染,把结果分别塞进两个 ul 的 innerHTML,用 Elements 面板对比生成的 DOM 是否完全一致。写一句话总结:为什么数组方法更不容易写出"覆盖式拼接"的 bug。

练习 2|猜数字·限定 5 次 + 剩余次数提示 把猜数字改为最多 5 次,猜对时提示"你用了 N 次猜对,还剩 M 次机会"。要求分别用两种写法实现: ① 开关变量 flag + break; ② 逻辑中断 flag && alert(...)。 最后故意在写法①里把 flag = false 挪到 break 后面,观察现象并解释原因。

练习 3|随机颜色函数升级 把 getRandomColor(flag) 改成接收字符串参数 getRandomColor(type = 'hex'),支持 'hex' / 'rgb',传入其他值或 undefined 时统一回退到十六进制。要求:颜色生成部分抽成两个小函数,主函数只负责分发。

练习 4|不重复抽名字 基于五虎上将数组做"抽一个少一个":每次随机抽出一个名字显示到页面,同时从数组中移除该元素;数组抽空后提示"已全部抽完"并停止。提示:注意移除后长度会变,随机公式里的长度必须是"当下"的长度。

练习 5|数据驱动验证 在学成在线数据里新增两条对象,不做任何 HTML 改动,只刷新页面确认列表变成 12 条;再故意把某条数据的 src 改成不存在的路径,观察页面表现,并说明为什么"改数据不改结构"是这个案例最大的价值。

原视频对照 ​

#视频时长
1随机显示姓名案例07:00
2猜数字游戏09:55
3猜数字游戏限定次数13:17
4随机颜色案例-封装函数07:41
5随机颜色案例-返回rgb格式颜色04:23
6随机颜色案例-返回十六进制格式颜色08:14
7综合案例-学成在线页面渲染13:24

小结 ​

  1. 累加型变量的作用域决定了结果正确性:字符串拼接、颜色拼接、开关标记,只要"跨轮次"使用,就必须声明在循环外面,这是本组案例最高频的翻车点。
  2. 对象数组 + 循环 + 字符串拼接 = 数据驱动渲染的雏形:页面结构写一次、数据变多次,后续学 Vue/React 的列表渲染本质上还是这套思路的语法升级。
  3. break 与开关变量是两件事:break 只终止循环,不向循环外传递"我成功了"这个信息;要靠 flag 之类的变量把状态带出去,且赋值必须在 break 之前。
  4. 逻辑中断 flag && alert() 是 if 的等价简化,但它只适合"条件为真就执行一句"的场景;条件分支多于两个时老老实实写 if/else,可读性优先。
  5. 随机数公式要背成"长度思维"而不是"数字思维":数组用 * arr.length,区间用 (max - min + 1) + min,后者是前者的推广,写错基本都是漏了 +1。
  6. 函数用形参控制返回值,是"一个函数多形态"的最小实践:布尔参数能用但语义弱,字符串/枚举参数更接近真实 API 设计;默认参数保证"不传也能跑"。
  7. 渲染入口要选对:document.write 是演示工具,innerHTML 才是工程手段;调试时看 Elements 里的真实 DOM,而不是只看页面"像不像"。
  8. 写这类案例的正确节奏是「先结构、再数据、最后换活数据」:先用死数据拼通结构并 console.log 验证条数,再逐个替换可变字段,比一上来就全动态化更容易定位错误。