跳转到内容

4.4 JavaScript 基础:让页面动起来

一、本节你会做出什么

你会在控制台里把一个景点数组变成一串名字(这正是 5.4 节渲染六张卡片的原理),并让 4.2 那个点了没反应的按钮真的弹出提示。

📷 效果位:控制台里 map 的输出结果

这一节是第 4 章里最“像编程”的一节,但目标还是那句话:不是让你会写,是让你看得懂、找得到问题。

明确一下这一节不教什么:语法细节、各种边界情况、“十种循环写法”。那些对你没用。本节只教你在 AI 写的代码里认出八样东西,以及一个你必须亲手练会的操作(map)。


二、开始前你需要

  • 已完成 4.3,页面已经装修过
  • 已完成 1.3,会打开浏览器控制台(本节全程在里面玩)

三、跟着做

第 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 // 3
attractions[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 一个前端项目由哪些文件组成