4.4 JavaScript 基础:让页面动起来
一、本节你会做出什么
你会在控制台里把一个景点数组变成一串名字(这正是 5.4 节渲染六张卡片的原理),并让 4.2 那个点了没反应的按钮真的弹出提示。
📷 效果位:控制台里 map 的输出结果
这一节是第 4 章里最“像编程”的一节,但目标还是那句话:不是让你会写,是让你看得懂、找得到问题。
明确一下这一节不教什么:语法细节、各种边界情况、“十种循环写法”。那些对你没用。本节只教你在 AI 写的代码里认出八样东西,以及一个你必须亲手练会的操作(map)。
二、开始前你需要
三、跟着做
第 1 步:JS 只干三件事
回到 4.1 的房子类比:HTML 是毛坯,CSS 是装修,JS 是电器和开关。
具体说,JS 在网页里只干这三件事:
| 它干什么 | 例子 |
|---|---|
| ① 响应用户操作 | 点按钮、填表单、滚动页面 |
| ② 改变页面内容 | 把数据变成卡片、显示/隐藏某块、切换深色模式 |
| ③ 和外部要数据 | 调接口拿景点列表、调 AI 让它生成文案(第 7、8 章) |
你看到的每一段 JS,都在干这三件事之一。 看代码时先判断它在干哪件,理解立刻就有了方向。
第 2 步:控制台就是你的游乐场
打开任意网页,按 F12 → Console(控制台) 面板。看到 > 提示符就可以输入了。
先热个身,一行一行敲(按回车执行):
1 + 1"成都" + "欢迎你"10 / 3💡 控制台和 2.1 的终端很像:都是打一行执行一行,都能用 ↑ 翻历史。区别是终端在指挥你的电脑,控制台在指挥这个网页。
📷 截图位 1:控制台里的几行计算结果
第 3 步:八样东西,认得就够
① 变量 —— 给数据起名字存起来
const city = "成都"; // const:定下来就不改了let count = 0; // let:之后会变| 关键字 | 意思 | 什么时候用 |
|---|---|---|
const |
常量,不会再改 | 默认都用这个(AI 代码里最多) |
let |
变量,后面会改 | 计数器、开关状态 |
var |
老写法 | 见到说明代码有年头了 |
② 四种基础数据
const name = "大熊猫基地"; // 字符串(文字,要加引号)const price = 55; // 数字(不加引号)const isOpen = true; // 布尔(只有 true / false 两个值)const image = null; // 空(明确表示"这里没有东西")🔑
undefined是你会最常见到的报错词。它的意思是「这个东西根本不存在」。 报错Cannot read property 'name' of undefined翻译过来就是: “你让我读某个东西的 name,但那个东西压根不存在。” 这是全课你会撞见最多的一条报错,现在就把它记住。
③ 数组 —— 一串东西
const foods = ["火锅", "串串", "钟水饺"];
foods.length // 3 —— 有几个foods[0] // "火锅" —— 第一个(注意:从 0 开始数!)foods[2] // "钟水饺"⚠️ 数组从 0 开始数。
foods[1]是第二个。这是新手最容易绕进去的地方,也是“少了一个”“多了一个”这类 bug 的常见来源。
④ 对象 —— 一条完整的数据
数组是“一串”,对象是“一条的各个字段”。把它想成表格里的一行:
const attraction = { name: "大熊猫繁育研究基地", price: 55, duration: "3 小时", isOpen: true};
attraction.name // "大熊猫繁育研究基地" —— 用点取值attraction.price // 55对应到表格:
| name | price | duration | isOpen |
|---|---|---|---|
| 大熊猫繁育研究基地 | 55 | 3 小时 | true |
⑤ 数组 + 对象 = 真实项目里的数据长相
这是本节最该看懂的一个形状。 第 5 章的景点数据就是这个样子:
const attractions = [ { name: "大熊猫基地", price: 55, tag: "必去" }, { name: "宽窄巷子", price: 0, tag: "免费" }, { name: "武侯祠", price: 50, tag: "文化" }];读出来就是:一张三行的表格。 外层 [] 是行的集合,每个 {} 是一行。
attractions.length // 3attractions[0].name // "大熊猫基地"🔑 以后在 AI 代码里看到
[{...}, {...}]这个形状,立刻想到“表格”。 这个直觉能帮你看懂大半数据相关的代码。
⑥ 函数 —— 一段起了名字、可以反复用的操作
function greet(name) { return "欢迎来到" + name;}
greet("成都") // "欢迎来到成都"| 部分 | 叫什么 | 说明 |
|---|---|---|
greet |
函数名 | 这段操作叫什么 |
(name) |
参数 | 用的时候要给它什么 |
return |
返回值 | 它算完之后交出什么 |
还有一种箭头函数写法,意思完全一样,AI 代码里很常见:
const greet = (name) => "欢迎来到" + name;看到
=>就知道“这是个函数”,不用深究两种写法的区别。
⑦ 条件 —— 分情况处理
if (price === 0) { console.log("免费");} else { console.log("要门票");}⚠️
===是“等于”,=是“赋值”。 写成=是经典 bug。你不写代码,但 review AI 的代码时见到if (x = 0)要警觉。
⑧ 事件 —— 用户干了什么,就触发什么
button.addEventListener("click", () => { alert("我想去!");});读出来:“给这个按钮装一个监听器,有人点击时,执行后面那个函数。”
🔑 4.1 定位表里「按钮点了没反应」,九成是这里出了问题:监听器没装上,或者函数里报错了。
第 4 步:动手——跑通 map(本节核心练习)
map 是整个第 5 章最重要的一个操作。 它的作用是:
把一个数组,变成另一个数组。
在控制台里逐段敲进去(整段粘贴也行):
const attractions = [ { name: "大熊猫基地", price: 55 }, { name: "宽窄巷子", price: 0 }, { name: "武侯祠", price: 50 }];
// 把"一串对象"变成"一串名字"const names = attractions.map(item => item.name);
names输出:
["大熊猫基地", "宽窄巷子", "武侯祠"]发生了什么:
[{name:"大熊猫基地",...}, {name:"宽窄巷子",...}, {name:"武侯祠",...}] │ │ │ 每一个都过一遍 item => item.name (取出 name) ↓ ↓ ↓ "大熊猫基地" "宽窄巷子" "武侯祠"item 是你给“每一项”起的临时名字(叫 a、叫 x 都行)。
再试两个,加深手感:
// 变成一串价格attractions.map(item => item.price)
// 变成一串描述文字attractions.map(item => item.name + " ¥" + item.price)📷 截图位 2:控制台里 map 的三次输出
🔑 为什么这个练习这么重要:
第 5.4 节要「用数组循环渲染 6 个景点」,干的就是这件事—— 把一个景点数组,
map成一串景点卡片。数据数组 ──map──► 卡片数组 ──► 页面上六张卡片你今天在控制台里把对象变成了文字;到那时是把对象变成了卡片。同一个动作。
第 5 步:动手——让 4.2 那个按钮真的能点
回到你的 index.html,在 </body> 前面加上:
<script> const btn = document.querySelector("button");
btn.addEventListener("click", () => { alert("已加入我的成都行程!"); });</script>保存、刷新、点按钮。弹出来了。
三行代码,三件事:
| 代码 | 在干什么 |
|---|---|
document.querySelector("button") |
在页面里找到那个按钮(document = 当前页面) |
addEventListener("click", ...) |
装上监听:有人点击时 |
alert(...) |
弹个提示框 |
💡
querySelector里面写的就是 4.3 的 CSS 选择器——"button"找标签,".card"找 class。JS 用的是和 CSS 同一套选择器,学一次用两处。
⚠️
alert只是练手用的。 真实项目里基本不用它(会卡住整个页面),正式做法是改页面内容或弹一个自定义提示框。
再试一个更有意思的,把上面的 alert 那行换成:
document.querySelector("h1").textContent = "我要去成都!";点按钮 → 大标题的文字变了。
这就是 JS 的本质:找到元素,改掉它。页面上所有的动态效果,拆到底都是这件事的组合。
第 6 步:怎么看懂 AI 写的 JS(本节真正的交付能力)
AI 甩给你 80 行 JS,千万不要从第一行开始逐行读。按这个顺序找四样东西:
| 顺序 | 找什么 | 怎么找 |
|---|---|---|
| 1 | 数据在哪 | 找 const xxx = [...] 或 useState(4.6 讲)。数据长什么样,决定了页面长什么样 |
| 2 | 函数叫什么名 | 找 function xxx 或 const xxx = () =>。好名字直接告诉你它干什么(handleSubmit = 处理提交) |
| 3 | 事件绑在哪 | 找 addEventListener 或 onClick。用户的操作从这里进入代码 |
| 4 | 数据怎么变成界面 | 找 .map(。这一行就是“数据 → 页面”的转换点 |
找到这四样,你就知道这段代码的骨架了,剩下的细节不用管。
🔑 还有一招:让 AI 加日志。
console.log()能把任何东西打印到控制台。搞不清某个值到底是什么,就跟 AI 说: 「在【某个位置】加一行 console.log,把【某个变量】打印出来,我想看看它的实际值。」
这是第 6 章排错的核心手段之一,比盯着代码猜有效得多。
第 7 步:两个概念先打个招呼
不用懂,见到不慌就行。
① async / await —— “等一下”
const data = await fetch("/api/attractions");await 的意思是:“这件事要花时间(比如去服务器要数据),等它回来再继续。”
见到 async / await,就知道“这里在等外部的东西”。第 7 章会讲透。
② 报错里的 undefined 和 null
| 报错片段 | 翻译 |
|---|---|
Cannot read properties of undefined |
你要读的那个东西不存在 |
xxx is not a function |
你把一个不是函数的东西当函数调用了 |
xxx is not defined |
这个名字根本没定义过(常常是拼写错了) |
这三条占了 JS 报错的一大半。不用你修——复制整段给 AI(1.3 的那条提示词),但认得它们能让你大致判断严重程度。
四、完成的标志是
- 我知道 JS 只干三件事:响应操作 / 改变页面 / 要外部数据
- 我分得清
const(不变)和let(会变) - 我知道数组从 0 开始数
- 我能把
[{...}, {...}]这个形状读成“一张表格” - 我认得函数的三部分:函数名、参数、返回值,看到
=>知道那是函数 - 我知道
===是比较、=是赋值 - 我在控制台里跑通了 map,把对象数组变成了名字数组
- 我给 index.html 加了 script,按钮点击真的有反应了
- 我试过用 JS 改掉 h1 的文字
- 我知道
querySelector用的是 CSS 选择器 - 我记住了看 JS 代码的四步:找数据、找函数名、找事件、找 map
- 我知道可以让 AI 加
console.log来看变量的实际值 - 我认得
undefined类报错大概在说什么
五、卡住了看这里
Q:控制台里报 Uncaught SyntaxError。
语法写错了——通常是引号、括号、大括号没配对。中文输入法打出的全角引号(“”)也是经典元凶,JS 只认半角 ""。按 ↑ 调出刚才那行,检查一遍。
Q:我在控制台定义了变量,刷新页面后没了。 正常。刷新 = 重新开始,控制台里的东西都是临时的。这也是好事——想重来就刷新。
Q:const attractions = ... 报错说 already been declared。
同一个名字在同一个页面里定义过两次了。刷新页面再敲一次,或者换个名字。
Q:按钮点了还是没反应。
三步查:① <script> 是不是放在 </body> 前面(放在 <head> 里会找不到按钮,因为按钮还没生成);② 控制台有没有红字;③ 在 addEventListener 前面加一行 console.log(btn),看打印出来的是按钮元素还是 null——是 null 就说明没找到元素。
Q:document.querySelector("button") 只找到了第一个按钮,我有好几个怎么办?
querySelector 只返回第一个匹配的。要全部就用 querySelectorAll。不过真实项目里更常见的做法是给元素加 class 来区分(4.2 讲的 class 又用上了)。
Q:这些我都要记住吗?感觉好多。
不用。真正需要你亲手练会的只有一个:map。 其余的是“认得”级别——看到 const 知道是变量、看到 => 知道是函数,就够了。这一节你三个月后回来看会觉得很简单。
Q:AI 写的 JS 我完全看不懂怎么办? 用本节提示词 ①。还有一个很好用的笨办法:让 AI 给每一行加中文注释,然后你读注释。读几个项目之后,你会发现代码的套路是高度重复的。
六、本节提示词
① 让 AI 讲解一段 JS(按第 6 步的四步法问):
我是零基础,正在学看懂 JavaScript。请讲解这段代码:【粘贴代码】
请按这个顺序讲,用大白话:1. **数据**:这段代码里的数据是什么形状?(是数组还是对象,有哪些字段)2. **函数**:定义了哪些函数,每个函数干什么?(从函数名能看出什么)3. **事件**:用户的什么操作会触发它?4. **界面**:数据是在哪一行变成页面上的东西的?5. 最后用三句话总结这段代码整体在干什么。
不要逐行翻译语法,我要的是整体理解。② 让 AI 加日志帮你定位(第 6 章会反复用):
我搞不清程序运行到某一步时的实际情况。
文件:【@文件名】我想知道:【比如"点击按钮时,传给函数的那个景点对象到底是什么"】
请在合适的位置加上 console.log,要求:1. 每条日志前面带一个标识,比如 console.log("[点击事件] 景点对象:", item);2. 只加日志,**不要改任何其他逻辑**;3. 告诉我加在了哪几行,以及我该怎么操作页面才能触发这些日志;4. 我看到日志后会贴给你。③ 报错急救(JS 专用):
我的页面出错了。
**操作**:我做了【具体操作,比如"点击了景点卡片"】**期望**:应该【期望的结果】**实际**:【实际发生的,比如"页面没反应"/"整页白屏"】
控制台报错原文(整段,包括下面的调用栈):【粘贴】
请你:1. 把这条报错翻译成大白话;2. 说明最可能的原因;3. 告诉我该怎么验证这个猜测(比如在哪儿加个 console.log 看什么);4. **先不要改代码**,等我确认原因后再动手。上一节 ← 4.3 CSS 基础与 Tailwind 下一节 → 4.5 一个前端项目由哪些文件组成