大家好,我是程序员柏风,AI 最全的 Vibecoding 学习地图 http://coderoadmap.cn 作者。
JavaScript:变量、函数与 DOM 操作
这一课你将能做到
- 用变量、函数、条件判断和循环写出可复用的逻辑代码
- 用 DOM API 读取和修改页面内容,实现点击按钮更新文字
- 用事件监听和 ES6+ 语法(箭头函数、解构、模板字符串)写出符合现代规范的代码
为什么要学
HTML 给结构,CSS 给样式,JavaScript 给行为。没有 JS,网页就是一张静止的画;有了 JS,它可以响应点击、提交表单、拉取数据、动态更新内容。现代前端工程师写的代码,80% 以上是 JavaScript。
对初学者来说,JS 的门槛在于它同时有「命令式编程」(一步步告诉电脑怎么做)和「声明式/函数式」两种风格,浏览器环境还引入了异步、事件循环等概念。但入门阶段只需要掌握基础语法和 DOM 操作,就能做出真正有交互的页面。
先建立图像
浏览器内部执行 JS 的流程:
你写的 .js 文件
↓
浏览器解析 → 变量提升 → 执行代码 → 操作 DOM/发请求
↓
DOM 树发生变化 → 浏览器重绘页面 → 用户看到变化
JS 是单线程的,同一时间只能做一件事,但事件循环让它看起来像「同时做多件事」。这个概念后面会深入,入门阶段先记住:代码从上到下执行,事件回调在主线空闲时执行。
跟着做
步骤 1:变量、数据类型与运算符
新建 script.js,在 index.html 的 </body> 前引入:
<script src="script.js"></script>
// 变量声明:const 不可重新赋值,let 可重新赋值
const siteName = "学习站";
let visitCount = 0;
// 基本数据类型
const isActive = true; // 布尔
const price = 199.9; // 数字(JS 不区分 int 和 float)
const description = "前端课程"; // 字符串
const tags = ["html", "css", "js"]; // 数组
const user = { // 对象
name: "张三",
age: 25,
isVip: false
};
// 模板字符串:反引号 + ${}
const greeting = `欢迎来到 ${siteName},当前访客数 ${visitCount}`;
console.log(greeting);
// 运算符
visitCount++; // 自增
const total = price * 1.2; // 算术
const canAccess = user.isVip || price === 0; // 逻辑
const hasTag = tags.includes("css"); // 数组方法
建议:默认用 const,只有需要重新赋值时才用 let。不要用 var,它有作用域提升问题,在现代代码中已淘汰。
步骤 2:函数与箭头函数
// 传统函数声明
function add(a, b) {
return a + b;
}
// 函数表达式
const multiply = function (a, b) {
return a * b;
};
// 箭头函数(现代项目最常用)
const divide = (a, b) => a / b;
// 多行箭头函数需要 return
const formatUser = (user) => {
const level = user.age >= 18 ? "成年" : "未成年";
return `${user.name}(${level})`;
};
console.log(add(2, 3)); // 5
console.log(formatUser(user)); // 张三(成年)
箭头函数和传统函数有一个关键区别:this 的绑定方式不同。入门阶段先记住:回调函数(比如事件监听、数组方法)优先用箭头函数,类方法或需要动态 this 时用传统函数。
步骤 3:条件判断与循环
// if / else
function getDiscount(user) {
if (user.isVip) {
return 0.8;
} else if (user.age >= 60) {
return 0.9;
} else {
return 1.0;
}
}
// 三元表达式(简短条件)
const statusText = user.isVip ? "VIP 用户" : "普通用户";
// 循环
for (let i = 0; i < tags.length; i++) {
console.log(tags[i]);
}
// 数组高阶方法(现代写法,推荐)
tags.forEach((tag) => console.log(tag));
const upperTags = tags.map((tag) => tag.toUpperCase());
console.log(upperTags); // ["HTML", "CSS", "JS"]
const longTags = tags.filter((tag) => tag.length > 2);
console.log(longTags); // ["html", "css"]
map、filter、forEach 是 JS 数组三大高阶方法,实际工作中出现的频率极高,必须熟练。
步骤 4:DOM 操作
DOM(Document Object Model)是浏览器把 HTML 解析成的树形结构,JS 通过 DOM API 来读写页面:
// 读取元素
const title = document.querySelector("h1");
const items = document.querySelectorAll(".item");
// 修改内容
title.textContent = "新标题";
// 修改样式
title.style.color = "#e63946";
// 修改属性
title.setAttribute("data-level", "1");
// 创建并插入元素
const newDiv = document.createElement("div");
newDiv.className = "card";
newDiv.textContent = "动态添加的内容";
document.body.appendChild(newDiv);
// 删除元素
const old = document.querySelector(".old");
if (old) old.remove();
querySelector 和 querySelectorAll 是万能选择器,支持 CSS 选择器语法,已经取代了旧的 getElementById/getElementsByClassName。
步骤 5:事件监听
<button id="clickBtn">点击我</button>
<input id="nameInput" placeholder="输入名字">
<p id="output"></p>
const btn = document.querySelector("#clickBtn");
const input = document.querySelector("#nameInput");
const output = document.querySelector("#output");
// 点击事件
btn.addEventListener("click", () => {
output.textContent = `你好,${input.value || "访客"}!`;
});
// 输入事件(实时响应)
input.addEventListener("input", (event) => {
output.textContent = `正在输入:${event.target.value}`;
});
事件监听是现代 JS 交互的核心模式:addEventListener 绑定事件 → 用户触发 → 回调函数执行 → 操作 DOM → 页面更新。
步骤 6:ES6+ 常用语法
// 解构赋值
const { name, age } = user;
const [first, second] = tags;
// 展开运算符
const newTags = [...tags, "react"];
const newUser = { ...user, city: "北京" };
// 默认参数
const greet = (name = "访客") => `你好,${name}`;
// 可选链(防止深层对象报错)
const city = user?.address?.city ?? "未知";
// Promise 基础(异步操作)
function fetchData() {
return fetch("https://api.github.com/users/github")
.then((res) => res.json())
.then((data) => console.log(data.login))
.catch((err) => console.error("出错了", err));
}
讲清楚要点
- JS 是弱类型语言:变量不声明类型,同一变量可以先存数字再存字符串。类型转换时要小心:
"5" + 1等于"51","5" - 1等于4。 ==和===的区别:==会做类型转换后比较("5" == 5为 true),===要求类型和值都相同。始终用===和!==,避免隐式转换的坑。- 数组方法不改变原数组:
map、filter、slice返回新数组;push、pop、splice改变原数组。React 中尤其要注意,优先用不可变方法。 - DOM 操作是同步但昂贵的:每次修改 DOM 都可能触发浏览器重排(reflow)和重绘(repaint)。频繁修改时先操作文档片段,或一次性修改完。
- 事件委托减少监听器数量:如果列表有 100 个 item,不要给每个 item 绑点击事件,而是给父容器绑一个,通过
event.target判断点的是谁。
你可能会懵的地方
-
为什么
var不能用?var是函数作用域,会提升到函数顶部,在循环中容易出现闭包陷阱。let和const是块级作用域({}内有效),行为更可预期。 -
this到底指向谁? 简单规则:普通函数里this指向调用者;箭头函数里this指向定义时的上下文(外层作用域)。事件回调用箭头函数可以避免this指向事件目标的问题。 -
为什么我的 DOM 操作报错 null?
<script>放在<head>里时,JS 执行时 body 还没解析。解决:把<script>放在</body>前,或加defer属性:<script src="..." defer></script>。 -
null和undefined有什么区别?undefined表示「声明了但还没赋值」;null表示「赋值为空」。typeof null是"object",这是 JS 的历史 bug,记住就行。 -
Promise 和 async/await 是什么关系?
async/await是 Promise 的语法糖,让异步代码看起来像同步。入门阶段先会用fetch().then(),后面再学async function和await。
错法对照
| 错法 | 问题 | 正解 |
|---|---|---|
var x = 1 | 作用域提升、不可预期 | const / let |
"5" == 5 | 隐式类型转换导致误判 | 始终用 === |
const arr = []; arr.push(1) | 误以为 const 数组不可改 | const 锁引用,不锁内容 |
document.querySelector("btn") | 少了 # 或 . | 按 CSS 选择器写:#btn |
<script> 放 head 且无 defer | DOM 未就绪就执行 | 放 body 末尾或用 defer |
for (var i=0; i<3; i++) { setTimeout(..., i) } | var 提升导致输出全是 3 | 用 let 或传参 |
user.name 时 user 是 undefined | 直接报错中断执行 | 用可选链 user?.name |
卡点急救
- 控制台报错
Cannot read properties of null:选择器写错,或 JS 在 DOM 加载前执行。检查选择器语法、script 标签位置。 - 点击按钮没反应:检查
addEventListener的拼写、事件名(是"click"不是"onclick")、选择器是否命中元素。 - 数组
map后页面没更新(React 中):React 要求不可变更新,不能直接push,要用setState([...old, newItem])。 fetch请求报 CORS 错:浏览器安全策略限制,不是代码问题。自己的后端加 CORS 头,或前端用代理。
面试常问
-
==和===的区别?==比较前会做类型转换,===严格比较值和类型。推荐始终用===。 -
什么是闭包? 函数内部引用了外部作用域的变量,即使外部函数已经执行完毕,这些变量仍被保留。常用于数据封装、柯里化、事件回调保留状态。
-
事件冒泡和事件捕获? 事件从目标元素向外传递到 document 叫冒泡(bubble);从 document 向内传到目标叫捕获(capture)。默认是冒泡阶段触发。
stopPropagation()阻止继续冒泡。 -
let、const、var的区别?var函数作用域、可重复声明、存在提升;let和const块级作用域、不可重复声明、const声明后不能重新赋值引用。TDZ(暂时性死区):let/const声明前访问会报错。
自测三问
- 写出一段代码:点击按钮,读取 input 的值,在页面上显示「你好,xxx」。
map和forEach的区别是什么?各自返回什么?- 用解构赋值从
{ name: "A", age: 20 }中取出 name,并给 age 一个默认值 18。
小结一句话
JavaScript 用变量存数据、用函数封装逻辑、用 DOM API 连接页面——三者结合,你就能写出有交互的真实网页。
延伸
- MDN JavaScript 基础
- 下一课:Git——管理代码版本,再也不怕改坏代码回不去。