主题
1-15对象和对象操作(二)
本页对应 第一章JavaScript基础,共 4 段视频,约 45 分钟。
学习目标
- 能识别并编写对象数组,使用传统
for循环遍历数组,并通过数组名[i].属性名取出每个对象的指定属性值。 - 能根据对象数组的数据条数,使用模板字符串和循环拼接表格行
<tr>,并将结果插入tbody,实现数据驱动的表格渲染。 - 能说明
Math是 JavaScript 内置数学对象,并能正确调用Math.PI、Math.max()、Math.min()、Math.abs()、Math.ceil()、Math.floor()、Math.round()完成对应数学运算。 - 能区分
Math.ceil()、Math.floor()、Math.round()在正数和负数场景下的取整规则,并正确预测和验证运行结果。 - 能使用
Math.random()生成[0, 1)范围内的随机小数,并说明其“能取到 0、取不到 1”的取值范围特点。 - 能推导并运用
Math.floor(Math.random() * (m - n + 1)) + n生成n到m之间的随机整数,并通过多次运行验证边界值。
知识点
从 console.log 认识内置对象
为什么需要:JavaScript 已经帮我们准备了一些常用对象,开发者不用从零写起,直接调用属性和方法即可,能提高开发效率。
怎么想:先分清“对象”和“对象里的方法”。console 是内置对象,log 是它里面的方法,所以写成 console.log()。
怎么做:遇到 Math、document 这类名字,先意识到它们可能是内置对象,再通过“对象.属性”或“对象.方法()”调用。
易错点:转写稿里把 Math 说成“mice/ms”,这是口误或同音,正确写法是 Math;方法后面要加小括号,属性一般不加。
Math 数学对象:属性和常用方法
为什么需要:做数学运算时,圆周率、最大值、最小值、绝对值、取整等都很常见,Math 把这些能力内置好了。
怎么想:先看它是属性还是方法。Math.PI 是属性;Math.max()、Math.ceil() 是方法。取整类要结合数轴理解“往大取”还是“往小取”。
怎么做:按下表调用,并通过 console.log 观察结果。
| 属性/方法 | 作用 | 说明 |
|---|---|---|
| PI | 圆周率 | Math.PI 属性,返回圆周率 |
| max | 找最大值 | Math.max(8, 3, 1) 方法,返回 8 |
| min | 找最小值 | Math.min(8, 3, 1) 方法,返回 1 |
| abs | 绝对值 | Math.abs(-1) 方法,返回 1 |
| ceil | 向上取整 | Math.ceil(3.1) 方法,返回 4 |
| floor | 向下取整 | Math.floor(3.8) 方法,返回 3 |
| round | 四舍五入取整 | Math.round(3.8) 方法,返回 4, 遇到.5则舍入到相邻的在正无穷(+∞)方向上的整数 |
易错点:max/min 的小括号里放数字,不要直接放数组;ceil 可记成“天花板”,往大了取;floor 可记成“地板”,往小了取。转写稿调试时特别强调负数:Math.ceil(-1.1) 得 -1,因为 -1 比 -2 大;Math.floor(-1.1) 得 -2,因为 -2 更小。Math.round(-1.5) 得 -1,因为 .5 要往正无穷方向取。
javascript
<script>
// 内置对象Math
// 1. PI 属性 圆周率
console.log(Math.PI)
// 2. max 方法 找最大值
console.log(Math.max(8, 4, 2)) // 8
// 3. min 方法 找最小值
console.log(Math.min(8, 4, 2)) // 2
// 4. abs 方法 取绝对值
console.log(Math.abs(-1)) // 1
// 5. ceil 方法 向上取整 ceil 天花板 往大了取
console.log(Math.ceil(1.1)) // 2
console.log(Math.ceil(1.5)) // 2
console.log(Math.ceil(1.8)) // 2
console.log(Math.ceil(-1.1)) // -1
console.log(Math.ceil(-1.5)) // -1
console.log(Math.ceil(-1.8)) // -1
// 6. floor 方法 向下取整 floor 地板 往小了取
console.log(Math.floor(1.1)) // 1
console.log(Math.floor(1.5)) // 1
console.log(Math.floor(1.8)) // 1
console.log(Math.floor(-1.1)) // -2
console.log(Math.floor(-1.5)) // -2
console.log(Math.floor(-1.8)) // -2
// 7. round 方法 四舍五入取整
console.log(Math.round(1.1)) // 1
console.log(Math.round(1.5)) // 2
console.log(Math.round(1.8)) // 2
console.log(Math.round(-1.1)) // -1
console.log(Math.round(-1.8)) // -2
console.log(Math.round(-1.5)) // -1
</script>随机数 random
为什么需要:随机点名、随机抽奖、随机取数组元素都需要随机整数,而 Math.random() 正好能提供随机小数。
怎么想:Math.random() 返回 [0, 1),即能取到 0、取不到 1,数学上叫“左闭右开”。要 0~10 的随机整数,就把它乘 (10 + 1),再向下取整。
怎么做:先乘范围,再 Math.floor 去掉小数。转写稿的推导是:(0~0.999…) * 11 得到 0~10.999…,向下取整后就是 0~10。5~15 可先做 0~10,再加 5。
易错点:不要忘记 +1;不要用 ceil 代替 floor;边界调试时可多刷新几次,观察能取到 0 和 10、5 和 15,但不会出现 11 或 16。
如何生成0-10的随机整数呢?
javascript
Math.floor(Math.random() * (10 + 1))如何生成5-15的随机整数?
javascript
Math.floor(Math.random() * (10 + 1)) + 5如何生成N-M之间的随机整数
javascript
Math.floor(Math.random() * (M - N + 1)) + N
Math.floor(Math.random() * (差值 + 1)) + 最小值javascript
<script>
// 1. Math随机数 Math.random()
// 1.1 随机的小数 0 ~1 之间
// 1.2 能取到0,但是取不到1 [0, 1)
// console.log(Math.random())
// 2. 取 0 ~ 10 之间的一个随机整数
// Math.random() * (10 + 1)
// (0 ~ 0.99999) * 11
// 0 ~ 10.99999
// Math.floor(Math.random() * (10 + 1))
// console.log(Math.floor(Math.random() * (10 + 1)))
// 3. 取 5 ~ 15 之间的一个随机整数
// Math.floor(Math.random() * (10 + 1)) 0 ~ 10
// Math.floor(Math.random() * (10 + 1)) + 5 5 ~ 15
// console.log(Math.floor(Math.random() * (10 + 1)) + 5)
// 4. 取 n ~ m 之间的一个随机整数 4 ~ 12
// Math.floor(Math.random() * (差值 + 1)) + 最小值
console.log(Math.floor(Math.random() * (8 + 1)) + 4)
</script>案例需求与效果

本节要做一个“学成在线”精品课程列表的综合案例:根据对象数组中的数据,渲染出多个课程列表项。
为什么需要:真实页面中的课程、商品、学生信息通常不是手写死的,而是来自一组结构化数据;数据一变,页面就应跟着变。
怎么想:先准备对象数组,再循环数组,把每个对象拼成一段li标签字符串,最后把字符串写入页面容器。
怎么做:核心是“对象数组 + for循环 + 模板字符串拼接 + document.write渲染”。
易错点:不要把数组和对象混淆;data[i]才是数组中的某个对象,data[i].title才是对象属性。
用对象数组组织数据
为什么需要:一个课程包含图片、标题、学习人数等多个信息,用多个变量保存很麻烦;把“课程对象”放进数组,就能描述一组课程。
怎么想:转写稿中讲对象数组时,先用students[i]取出数组中的每个对象,再用students[i].home取对象属性。本案例同理:data是数组,data[i]是课程对象。
怎么做:定义let data = [...],每项包含src、title、num。
易错点:data.length表示对象个数;循环条件写i < data.length,不要写i <= data.length,否则会取到undefined。
循环拼接字符串生成标签
为什么需要:有11条数据就手写11个li,数据一变就要改HTML,维护成本高。
怎么想:先准备空字符串let str = '',循环一次就向str追加一个li;循环结束后,str里就是所有列表项。
怎么做:用传统for循环遍历数组,在模板字符串中通过\${data[i].src}、\${data[i].title}、\${data[i].num}填入真实数据。转写稿里调试表格案例时,会先console.log(str)检查是否生成了对应行数;本案例也可以先打印str,确认拼接结果再写入页面。
易错点:模板字符串要用反引号;${}不能写成$();<li>标签要成对闭合;图片路径./uploads/...要真实存在。
写入容器完成渲染
为什么需要:拼接出的字符串还只是“字符串”,必须放进页面的ul容器中,浏览器才会把它解析成标签。
怎么想:先搭好课程模块外层结构.course.wrapper,再在.bd中的ul.common里放入\${str}。
怎么做:用document.write()输出整段模板字符串,把前面生成的str插入ul内部。
易错点:ul的类名要与CSS对应;document.write中的模板字符串里又嵌套了\${str},注意反引号成对;脚本写在body中时,生成内容会写入当前脚本位置。
完整代码
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>调试与验证
为什么需要:字符串拼接时少一个反引号、少一个},页面就可能空白或结构错乱。
怎么想:先验证数据,再验证拼接,最后验证渲染。
怎么做:先console.log(data.length)看条数;再console.log(str)看是否生成多个li;最后刷新页面检查图片、标题、人数。
易错点:num是数字,直接插入即可;若图片不显示,先查src路径;若列表样式不对,查ul.common和CSS类名是否一致。数据增加后无需改HTML,列表会自动多出一项,这正是数据驱动渲染的价值。
课件图示



代码示例
示例一:Math 内置对象的属性与方法
html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Math 内置对象</title>
</head>
<body>
<script>
// 内置对象 Math
// 1. PI 属性 圆周率
console.log(Math.PI)
// 2. max 方法 找最大值
console.log(Math.max(8, 4, 2)) // 8
// 3. min 方法 找最小值
console.log(Math.min(8, 4, 2)) // 2
// 4. abs 方法 取绝对值
console.log(Math.abs(-1)) // 1
// 5. ceil 方法 向上取整 ceil 天花板 往大了取
console.log(Math.ceil(1.1)) // 2
console.log(Math.ceil(1.5)) // 2
console.log(Math.ceil(1.8)) // 2
console.log(Math.ceil(-1.1)) // -1
console.log(Math.ceil(-1.5)) // -1
console.log(Math.ceil(-1.8)) // -1
// 6. floor 方法 向下取整 floor 地板 往小了取
console.log(Math.floor(1.1)) // 1
console.log(Math.floor(1.5)) // 1
console.log(Math.floor(1.8)) // 1
console.log(Math.floor(-1.1)) // -2
console.log(Math.floor(-1.5)) // -2
console.log(Math.floor(-1.8)) // -2
// 7. round 方法 四舍五入取整
console.log(Math.round(1.1)) // 1
console.log(Math.round(1.5)) // 2
console.log(Math.round(1.8)) // 2
console.log(Math.round(-1.1)) // -1
console.log(Math.round(-1.8)) // -2
console.log(Math.round(-1.5)) // -1
</script>
</body>
</html>关键行与易错点
Math是内置的数学对象,PI是属性(不带小括号),max / min / abs / ceil / floor / round都是方法(必须带小括号),写成Math.PI而不是Math.pi,Math的 M 要大写。Math.max()/Math.min()括号里只能放数字,不能直接放数组,否则得不到最大值最小值。ceil记成“天花板”、floor记成“地板”:ceil往大了取、floor往小了取,负数时最容易错——Math.ceil(-1.1)是-1(比 -2 大),Math.floor(-1.1)是-2(比 -1 小)。round普通小数看离哪边近;遇到.5这种正好在中间的,舍入到正无穷方向的整数,所以Math.round(-1.5)是-1而不是-2。
示例二:Math.random 生成随机整数
html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Math.random 随机数</title>
</head>
<body>
<script>
// 1. Math随机数 Math.random()
// 1.1 随机的小数 0 ~ 1 之间
// 1.2 能取到0,但是取不到1 [0, 1)
console.log(Math.random())
// 2. 取 0 ~ 10 之间的一个随机整数
// Math.random() * (10 + 1)
// (0 ~ 0.99999) * 11
// 0 ~ 10.99999
// Math.floor(Math.random() * (10 + 1))
console.log(Math.floor(Math.random() * (10 + 1)))
// 3. 取 5 ~ 15 之间的一个随机整数
// Math.floor(Math.random() * (10 + 1)) 0 ~ 10
// Math.floor(Math.random() * (10 + 1)) + 5 5 ~ 15
console.log(Math.floor(Math.random() * (10 + 1)) + 5)
// 4. 取 n ~ m 之间的一个随机整数 4 ~ 12
// Math.floor(Math.random() * (差值 + 1)) + 最小值
console.log(Math.floor(Math.random() * (8 + 1)) + 4)
</script>
</body>
</html>关键行与易错点
Math.random()返回[0, 1)的随机小数:能取到 0,取不到 1(左闭右开)。- 因为取不到 1,所以公式里必须
(差值 + 1),少加这个 1 就永远取不到最大值;最后一定要用Math.floor把小数“砍掉”,不能用Math.ceil(会把范围撑大)。 - 通用公式:
Math.floor(Math.random() * (M - N + 1)) + N,其中M - N是最大值减最小值的差值,N是最小值。 - 5~15 的例子本质是“0~10 的公式整体 +5”,因为差值
15 - 5 = 10;0~10 的例子最小值是 0,加 0 和不加一样,所以看起来没写+ 0。
示例三:综合案例——根据对象数组渲染列表页面
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)
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是对象数组(数组里存的是对象),所以遍历的是数组,用传统for循环:for (let i = 0; i < data.length; i++),不要写成for...in。data[i]拿到的是数组里的每一个对象,再通过data[i].src、data[i].title、data[i].num这种“对象.属性”的方式取出具体值。- 拼接必须先用
let str = ''准备一个空字符串,循环里用str +=累加;如果写成str =,最后只剩一条数据。 - 模板字符串里的
${}中直接写data[i].src即可,别再手写+号拼接,也不要在${}外面再加引号,否则属性值会变成死字符串。 - 用
document.write()输出时,\${str}要放在<ul class="common">内部,生成的多个li才会成为ul的子元素;页面上有几个li完全由data的长度决定,增删数据不需要改页面结构。
常见错误
1. 把数组直接丢给 Math.max / Math.min
- 现象:
Math.max([8, 3, 1])得到NaN,而不是8。 - 原因:这两个方法接收的是"一串数字参数",不是"一个数组",数组被当成一个值参与比较,转数字失败。
- 修法:展开后再传
Math.max(...arr),或Math.max.apply(null, arr);只传数字时直接用Math.max(8, 3, 1)。
2. 大小写写错,拿到 undefined 或直接报错
- 现象:
Math.pi得到undefined;math.PI直接抛ReferenceError: math is not defined。 - 原因:JS 区分大小写,对象名
Math、属性名PI都是固定写法。 - 修法:
Math.PI;遇到undefined先回头看属性名拼写,而不是怀疑公式。
3. 负数取整方向搞反
- 现象:以为
Math.ceil(-1.1)是-2,实际是-1;以为Math.floor(-1.1)是-1,实际是-2。 - 原因:把"向上/向下"理解成了"绝对值变大/变小",而它指的是数轴上的方向。
- 修法:写负数前先在纸上画数轴,
ceil往右(+∞)、floor往左(-∞);正数场景两者结果才是"去掉小数"。
4. Math.round(-1.5) 与直觉不符
- 现象:期望
-2,实际得到-1。 - 原因:
.5的舍入方向固定朝 +∞,不是"远离零"。 - 修法:需要"远离零"的四舍五入时写
Math.sign(x) * Math.round(Math.abs(x));普通业务(金额、评分)用默认行为即可。
5. 随机整数公式差 1,或边界永远取不到
- 现象:想要 0~10 却写成
Math.floor(Math.random() * 10),10 永远出不来;想要 5~15 写成Math.floor(Math.random() * 15) + 5,只能到 19 以内的错误区间。 - 原因:
Math.random()取不到 1,区间长度必须+1补齐;起始值只能加在最后。 - 修法:死记模板
Math.floor(Math.random() * (max - min + 1)) + min,任何范围都套它,不要临时推导。
6. 用 Math.round 生成随机整数,边界概率减半
- 现象:
Math.round(Math.random() * 10)能出 0~10,但统计下来 0 和 10 出现的次数只有其它数字的一半。 - 原因:
round把[0, 0.5)都归到 0,把[9.5, 10]归到 10,而中间每个整数各占一个完整区间。 - 修法:随机取整一律用
Math.floor,不要用round。
7. 渲染时数据取不到,页面出现 undefined
- 现象:列表里每行都显示
undefined,或最后多出一行空白。 - 原因:
\${data.src}少写了索引(data是数组不是对象);或循环条件写成i <= data.length,多跑一轮越界。 - 修法:模板里统一写
\${data[i].属性名};循环条件固定i < data.length。出现undefined先查索引。
8. 字符串拼接用 = 而不是 +=,只渲染最后一条
- 现象:数据有 10 条,页面只出现 1 条。
- 原因:每轮循环都用
str = ...覆盖了上一轮结果。 - 修法:
let str = ''初始化,循环内str += ...;变量必须初始化为空串,否则开头会多一个undefined。
练习
练习 1|取整预测
先不运行,写出下面每行的结果,再在控制台验证,错一个就把那条抄在笔记里:
javascript
Math.ceil(-2.3) // ?
Math.floor(-2.3) // ?
Math.round(-2.5) // ?
Math.round(2.5) // ?
Math.abs(-2.3) // ?练习 2|封装随机函数
写一个 randomInt(min, max),返回 [min, max] 闭区间内的随机整数(min、max 都能取到)。然后用它从笔记里的 data 数组中随机抽一门课,把标题打印到控制台。要求:连续刷新 20 次,结果里必须出现过 data 的第一条和最后一条。
练习 3|数据驱动渲染
用下面数组渲染成一个 <ul>,每行格式为 序号. 姓名(年龄):
javascript
let students = [
{ name: '小明', age: 18 },
{ name: '小红', age: 19 },
{ name: '小刚', age: 17 }
]要求:① 序号从 1 开始;② 渲染完成后,往数组末尾再 push 一条数据并重新渲染,页面自动变成 4 行,不需要改动任何 HTML。
练习 4|骰子统计
模拟掷骰子 1000 次(1~6 点),统计每个点数出现的次数并打印。跑完后回答:如果 6 个数字出现次数差距很大(比如某个点 300 次),问题最可能出在哪一行?
练习 5|找 bug
下面的代码想让页面渲染出 3 个课程标题,找出至少 3 处问题并改正:
javascript
let data = [{ title: 'A' }, { title: 'B' }, { title: 'C' }]
let str
for (let i = 0; i <= data.length; i++) {
str = `<li>${data.title}</li>`
}
document.body.innerHTML = str原视频对照
| # | 视频 | 时长 |
|---|---|---|
| 1 | 对象数组案例 | 07:25 |
| 2 | 渲染表格案例 | 10:53 |
| 3 | Math内置对象 | 15:50 |
| 4 | Math.random生成随机数 | 11:33 |
小结
Math是直接拿来用的工具对象,所有成员都是Math.xxx的调用形式,永远不要new Math(),也不要把它的方法当成全局函数直接写max()。- 取整三兄弟在正数上"看起来都对",真正的分歧全在负数——只要出现负数,先画数轴再写代码。
- 随机整数只有一个模板:
Math.floor(Math.random() * (max - min + 1)) + min,任何范围都套它,不要现场推导;取整一定用floor,用round会让两端概率减半。 - 对象数组 +
for循环 + 模板字符串+=拼接 + 一次性写入容器,是"数据驱动渲染"的最小原型;后面学的框架列表渲染,本质还是这一步。 - 页面渲染出几行由
data.length决定,不由 HTML 决定;数据改了页面就变,这才是这套写法真正的价值。 - 渲染结果出现
undefined,九成是三种情况:少了[i]、循环条件用了<=、字符串没初始化为空串或用=覆盖了。 - 写入容器优先用
innerHTML,document.write只在页面加载过程中可靠,一旦放进事件回调里会把整页清空。