本文是一份面向前端页面和主题开发的 JavaScript 实战指南,重点讲清楚语言基础、浏览器 DOM、事件、异步、模块、表单、请求、存储、性能、可访问性,以及在实际页面中如何组织脚本。它适合和 HTML、CSS、Nginx 静态资源、前端模板一起使用。
适用场景
- 编写网页交互逻辑
- 主题脚本开发
- 表单提交和异步请求
- DOM 操作和事件绑定
- 页面性能优化和可访问性
- 和后端 API 对接
JavaScript 是什么
JavaScript 是运行在浏览器和其他环境中的脚本语言。在前端页面里,它最常见的用途是:
- 处理用户交互
- 修改页面内容
- 发起网络请求
- 管理状态
- 控制动画和局部刷新
运行环境
JavaScript 可以运行在:
- 浏览器
- Node.js
- 服务端或边缘环境
本文主要关注浏览器场景。
基础语法
变量
let name = "Alice";
const age = 18;
var legacy = true;建议:
- 默认用 const
- 需要重新赋值时用 let
- 尽量少用 var
数据类型
- string
- number
- boolean
- null
- undefined
- object
- symbol
- bigint
条件
if (age >= 18) {
console.log("adult");
} else {
console.log("minor");
}循环
for (let i = 0; i < 3; i++) {
console.log(i);
}
for (const item of [1, 2, 3]) {
console.log(item);
}函数
function greet(name) {
return `Hello, ${name}`;
}
const add = (a, b) => a + b;严格模式
严格模式可以减少一些隐式错误。
"use strict";现代模块环境中通常默认更严格,但在老脚本里仍值得显式使用。
数组与对象
数组
const list = [1, 2, 3];
list.push(4);
const doubled = list.map((n) => n * 2);对象
const user = {
name: "Alice",
age: 18,
};解构
const { name, age } = user;
const [first, second] = list;展开
const nextUser = { ...user, role: "admin" };
const nextList = [...list, 5];DOM 操作
选择元素
querySelector() 会返回匹配到的第一个元素,找不到时返回 null。
const btn = document.querySelector("#submit");
const items = document.querySelectorAll(".item");修改内容
const el = document.querySelector("#title");
el.textContent = "New Title";修改属性
const img = document.querySelector("img");
img.setAttribute("alt", "Banner");类名操作
el.classList.add("active");
el.classList.remove("active");
el.classList.toggle("hidden");建议:
- 优先用 textContent
- 少用 innerHTML
- 对用户输入务必防止 XSS
事件
绑定事件
button.addEventListener("click", () => {
console.log("clicked");
});表单提交
form.addEventListener("submit", (event) => {
event.preventDefault();
});常见事件
- click
- input
- change
- submit
- focus
- blur
- keydown
- scroll
异步编程
JavaScript 的异步是核心能力之一。
回调
setTimeout(() => {
console.log("later");
}, 1000);Promise
Promise 表示一个未来完成或失败的操作。
const promise = new Promise((resolve) => {
resolve("ok");
});async / await
async function loadData() {
const res = await fetch("/api/data");
return await res.json();
}建议:
- 需要顺序执行的异步逻辑,用 async/await
- 需要并发执行的,考虑 Promise.all
并发
const [a, b] = await Promise.all([fetch("/a"), fetch("/b")]);Fetch
Fetch 是现代浏览器里最常用的请求方式。
GET 请求
const res = await fetch("/api/user");
const data = await res.json();POST 请求
await fetch("/api/message", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({ name: "Alice" }),
});错误处理
try {
const res = await fetch("/api/data");
if (!res.ok) throw new Error(`HTTP ${res.status}`);
const data = await res.json();
console.log(data);
} catch (err) {
console.error(err);
}表单处理
前端表单的关键点是:
- 校验
- 提示
- 禁用重复提交
- 处理成功和失败状态
示例:
form.addEventListener("submit", async (e) => {
e.preventDefault();
submitBtn.disabled = true;
try {
const formData = new FormData(form);
const res = await fetch("/api/submit", {
method: "POST",
body: formData,
});
if (!res.ok) throw new Error("submit failed");
} finally {
submitBtn.disabled = false;
}
});存储
localStorage
localStorage.setItem("theme", "dark");
const theme = localStorage.getItem("theme");sessionStorage
适合当前会话。
Cookie
用于需要随请求发送到服务端的数据。不要把敏感信息明文放进前端可控存储。
模块
导出
export function sum(a, b) {
return a + b;
}导入
import { sum } from "./utils.js";模块化的好处:
- 更容易维护
- 依赖更清晰
- 便于拆分代码
浏览器 API
常见有用 API:
- window
- document
- location
- history
- navigator
- localStorage
- fetch
- URL
- FormData
URL
const url = new URL(location.href);
console.log(url.searchParams.get("page"));FormData
const formData = new FormData(form);性能
资源加载
MDN 建议,对外部脚本优先考虑 defer,避免阻塞页面解析。
<script src="/static/js/app.js" defer></script>避免阻塞
- 大脚本放底部或使用 defer
- 不要无脑用大量同步 DOM 操作
- 避免频繁重排重绘
防抖和节流
function debounce(fn, delay) {
let timer;
return (...args) => {
clearTimeout(timer);
timer = setTimeout(() => fn(...args), delay);
};
}可访问性
使用语义化元素
- 按钮用 <button>
- 链接用 <a>
- 表单控件配 label
键盘可用
交互不要只依赖鼠标点击。
可读的状态
按钮禁用、加载中、错误提示要让用户能感知。
安全
XSS
不要把不可信内容直接塞进 innerHTML。
URL 注入
构建链接时注意编码和校验。
CSRF
前端请求时要配合后端的 CSRF 策略。
常见写法建议
- 先拿 DOM,再绑定事件
- 逻辑拆成小函数
- 数据和 UI 分开
- 用早返回减少嵌套
- 尽量避免全局变量
和你仓库中的主题系统关系
你仓库里的主题模板里已经有一些典型 JS 用法:
- 导航菜单切换
- 轮播图
- 表单提交
- 验证码刷新
- fetch() 请求
这说明 JS 代码更适合被拆成:
- 公共脚本
- 页面脚本
- 组件脚本
而不是所有逻辑都堆在一个大文件里。
最小可用模板
<script defer src="/static/js/app.js"></script>document.addEventListener("DOMContentLoaded", () => {
const btn = document.querySelector("#menu-btn");
const menu = document.querySelector("#menu");
if (!btn || !menu) return;
btn.addEventListener("click", () => {
menu.classList.toggle("open");
});
});常见问题
1. null 取到报错
说明选择器没匹配到元素。先判断元素是否存在。
2. 请求失败
检查:
- URL 是否正确
- CORS 是否放行
- 服务器是否返回非 2xx
3. 页面卡顿
检查:
- 事件里是否做了太多 DOM 操作
- 是否频繁读取和写入布局属性
- 是否有大循环
4. 脚本不执行
检查:
- script 标签路径
- defer / async
- DOM 是否已加载
结论
JavaScript 的核心不是“会不会写几句语法”,而是:
- 理解浏览器事件模型
- 能正确操作 DOM
- 能处理异步和请求
- 会组织模块和状态
- 能保证可访问性和安全性
如果你要,我可以继续把这篇文档扩成更深入的版本,例如:
- JavaScript 异步与 Promise 深度指南
- DOM 与事件实战模板
- 前端安全与 XSS 防护
- Node.js 基础入门
- 现代 JavaScript 模块化与工程化