变量声明
JavaScript 里声明变量,常用的是 let 和 const。更早的时候也会见到 var,但现在多数场景不再推荐。
var 的问题比较直接:它允许重复声明,还有变量提升。也就是说,变量看起来像是'先用后声明',实际拿到的往往是 undefined。再加上它只有函数作用域或全局作用域,不受块级作用域限制,写在 if、for 里也可能跑到外面去,排查起来很烦。
let 解决了这类老问题:不允许重复声明,也有块级作用域,但不能在声明前使用。
const 也有块级作用域,而且必须初始化。一般我会优先用 const,只有确实需要重新赋值时再换成 let。var 这类写法,除非是在读旧代码,不然没必要再碰。
DOM 树和 DOM 对象
获取 DOM 元素
在页面里找元素,document.querySelector('selector') 通常最顺手,返回第一个匹配项;document.querySelectorAll('selector') 会返回所有匹配项,结果是静态 NodeList,复杂选择器也能用。
类选择器
const firstItem = document.querySelector('.list-item');
const allItems = document.querySelectorAll('.list-item');
id 选择器
用 # 前缀匹配元素的 id。
const name = document.querySelector('#username');
标签选择器
直接写标签名就行。
const body = document.querySelector('body');
其它方式
通过 ID 获取元素
document.getElementById('id') 传入元素 ID,返回第一个匹配元素,不存在就返回 null。
const element = document.getElementById('header');
通过类名获取元素
document.getElementsByClassName('class') 返回动态 HTML 集合,里面是所有匹配的类名元素。
const elements = document.getElementsByClassName('menu-item');
通过标签名获取元素
document.getElementsByTagName('tag') 返回所有匹配标签的动态 HTML 集合。
const divs = document.getElementsByTagName('div');
DOM 元素内容及属性的修改
DOM 元素内容修改
常用的是 innerHTML、textContent 和 innerText。
innerHTML 会把 HTML 标签当成结构解析,适合插入带格式的内容;textContent 只当纯文本处理;innerText 会受 CSS 影响,通常更贴近页面'看见的文本'。
// 修改元素内容示例
const element = document.getElementById('target');
element.innerHTML = '<strong>加粗文本</strong>'; // 解析 HTML
element.textContent = '<strong>纯文本显示</strong>'; // 不解析 HTML
DOM 属性修改
标准 HTML 属性可以直接通过对象属性改,也可以用 setAttribute。自定义属性一般用 dataset 或 setAttribute。删属性则用 removeAttribute。
// 修改标准属性
const img = document.querySelector('img');
img.src = 'new-image.jpg'; // 直接属性赋值
img.setAttribute('alt', '新图片描述'); // 通用方法
// 操作自定义属性
img.setAttribute('data-custom', 'value');
const customValue = img.dataset.custom; // 通过 dataset 访问
批量修改多个元素
querySelectorAll 拿到节点列表后,直接用 for 循环处理就行。这个写法不花哨,但够稳。
样式类名操作
classList 是我更愿意用的方式,add、remove、toggle、contains 都很清晰。相比直接拼 className 字符串,它不容易把原有类名弄丢。
add(className):添加一个或多个类名,重复添加不会报错remove(className):删除一个或多个类名,不存在也不会报错toggle(className):有就删,没有就加contains(className):判断是否包含某个类名,返回布尔值
const box = document.getElementById('box');
box.classList.add('active'); // 添加类
box.classList.remove('inactive'); // 移除类
box.classList.toggle('visible'); // 切换类
box.className = 'new-class'; // 更换类
替换类名
classList.replace(oldClass, newClass) 适合直接切换样式类型。
// 将 box 的 big 类替换为 small 类
box.classList.replace('big', 'small');
console.log(box.className); // 输出:box small
为什么更推荐 classList
直接改 className 往往要自己拼字符串,简单场景还能忍,复杂一点就容易出错。
// 传统方式(会覆盖原有类名)
box.className = 'active'; // 原本的 box 类会被覆盖,只剩 active
// 改进的传统方式(需要手动拼接)
box.className = box.className + ' active'; // 需要注意空格
// classList 方式(推荐)
box.classList.add('active'); // 原有类名不变,新增 active
注意事项
classList只管类名,不管id、data-*这类属性。- 传参时不要带
.,要写add('active'),不是add('.active')。 add、remove都支持多个类名,比如add('a', 'b', 'c')。- 现代浏览器都支持,IE10+ 也没问题,日常开发够用了。
检查类名是否存在
contains 可以判断元素有没有某个类名。
if (element.classList.contains('active')) {
console.log('Element has active class');
}
表单元素值操作
input、select 这类表单控件,一般直接读写 value。复选框和单选按钮则看 checked。
const input = document.getElementById('username');
input.value = '新用户'; // 修改输入值
const checkbox = document.getElementById('agree');
checkbox.checked = true; // 选中复选框
使用 style 属性修改样式
需要临时改样式时,可以直接操作元素的 style。这种方式适合动态变化,或者临时覆盖内联样式。
element.style.property = value;
<!DOCTYPE html>
<html>
<body>
<div>测试盒子</div>
<button onclick="changeStyle()">修改样式</button>
<script>
const box = document.getElementById('myBox');
function changeStyle() {
// 1. 修改单个样式(驼峰命名)
box.style.backgroundColor = 'red'; // 背景变红
// 2. 修改多个样式
box.style.width = '200px';
box.style.height = '200px';
box.style.borderRadius = '10px';
box.style.color = 'white';
box.style.fontSize = '16px';
// 3. 清空单个样式(设为空字符串)
// box.style.border = '';
}
</script>
</body>
</html>
常见样式属性:
color:修改文本颜色backgroundColor:修改背景颜色fontSize:修改字体大小width/height:修改元素宽高display:控制显示方式,比如none隐藏元素
注意事项
- CSS 属性名要转成驼峰,比如
font-size写成fontSize,border-top写成borderTop。 - 数值类样式一般要带单位,比如
px、rem,不然不会生效。 style写进去的是行内样式,优先级比类样式高,!important例外。- 想恢复默认样式,可以把属性值设为空字符串,比如
box.style.backgroundColor = ''。
通过 JavaScript 修改样式
这和上面那段其实是一回事,只是写法更直白:先拿到元素,再改 style。
const element = document.getElementById("myElement");
element.style.color = "red";
element.style.fontSize = "16px";
获取表单里的值
方法 1:通过元素 ID 直接获取
这是最省事的写法。给表单元素加上唯一 id,然后通过 document.getElementById() 取值。
<!DOCTYPE html>
<html>
<body>
<form>
<label>用户名:</label><input type="text"><br>
<label>密码:</label><input type="password"><br>
<label>性别:</label>
<input type="radio" name="gender" value="男">男
<input type="radio" name="gender" value="女">女<br>
<button type="button" onclick="getFormValueById()">获取值</button>
</form>
<script>
function getFormValueById() {
// 获取输入框、密码框的值
const username = document.getElementById('username').value;
const password = document.getElementById('password').value;
// 获取单选框的值
const male = document.getElementById('male');
const female = document.getElementById('female');
const gender = male.checked ? male.value : female.checked ? female.value : '未选择';
console.log('用户名:', username);
console.log('密码:', password);
console.log('性别:', gender);
}
</script>
</body>
</html>
方法 2:通过表单对象获取
如果表单项比较多,直接从表单对象里按 name 取,会更顺手一点。
<!DOCTYPE html>
<html>
<body>
<form>
<label>用户名:</label><input type="text" name="username"><br>
<label>爱好:</label>
<input type="checkbox" name="hobby" value="读书">读书
<input type="checkbox" name="hobby" value="运动">运动
<input type="checkbox" name="hobby" value="游戏">游戏<br>
<label>城市:</label>
<select name="city">
<option>请选择</option>
<option value="北京">北京</option>
<option value="上海">上海</option>
</select><br>
<button type="button" onclick="getFormValueByForm()">获取值</button>
</form>
<script>
function getFormValueByForm() {
// 获取表单对象
const form = document.getElementById('userForm');
// 获取普通输入框、下拉框的值(通过 name)
const username = form.username.value;
const city = form.city.value;
// 获取复选框的值
const hobbies = [];
form.hobby.forEach(item => {
if (item.checked) {
hobbies.push(item.value);
}
});
console.log('用户名:', username);
console.log('城市:', city);
console.log('爱好:', hobbies);
}
</script>
</body>
</html>
H5 自定义属性 data-
一、如何定义 data-* 自定义属性
自定义属性要以 data- 开头,后面可以接任意命名。实际写的时候,建议小写配连字符,可读性最好。
<!DOCTYPE html>
<html>
<body>
<!-- 单个自定义属性 -->
<div>用户信息</div>
<!-- 多个自定义属性 -->
<ul>
<li>智能手机</li>
<li>笔记本电脑</li>
</ul>
<!-- 带连字符的自定义属性(推荐命名方式) -->
<button>操作按钮</button>
</body>
</html>
二、在 JavaScript 中操作自定义属性
常见做法有两种,实际开发里我更倾向于 dataset,语义清楚,也更贴近 HTML5 的设计。
方式 1:使用 dataset
dataset 会把所有 data-* 属性收进来,读取时会自动去掉 data- 前缀;带连字符的命名也会转成驼峰。它读出来的值都是字符串,数字或布尔值要自己转一下。另外,别拿它存密码这类敏感信息,控制台里看得到。
<script>
// 1. 获取单个元素的自定义属性
const userDiv = document.getElementById('user');
// 获取 data-id
console.log(userDiv.dataset.id); // 输出:1001
// 2. 获取带连字符的自定义属性(自动转驼峰)
const btn = document.querySelector('button');
console.log(btn.dataset.userStatus); // 输出:active
console.log(btn.dataset.userRole); // 输出:admin
// 3. 设置自定义属性
userDiv.dataset.name = '张三';
userDiv.dataset.age = 25;
console.log(userDiv.dataset.name); // 输出:张三
// 4. 遍历所有自定义属性
const productLi = document.querySelector('li');
for (let key in productLi.dataset) {
console.log(key + ': ' + productLi.dataset[key]);
}
// 5. 删除自定义属性
delete userDiv.dataset.age;
console.log(userDiv.dataset.age); // 输出:undefined
</script>
注意事项
定时器——间歇函数
JavaScript 里常见的两个定时器是 setTimeout() 和 setInterval(),都属于 window 对象。一个负责延时一次执行,一个负责按固定间隔重复执行。
1. setTimeout():一次性延时执行
setTimeout() 用来指定一段时间后执行一次函数,执行完就结束。
语法:
let timerId = setTimeout(callback, delay, param1, param2, ...);
callback 是延时后执行的函数;delay 是毫秒数;后面的参数会原样传给回调函数;timerId 是定时器标识,后面清除它要靠这个值。
示例代码:
<!DOCTYPE html>
<html>
<body>
<button onclick="stopMyTimeout()">停止延时任务</button>
<script>
// 示例1:基础用法(3 秒后执行)
const timer1 = setTimeout(() => {
alert('3秒到了!');
}, 3000);
// 示例2:带参数的回调函数
const timer2 = setTimeout((name, age) => {
console.log(`你好${name},年龄${age}`); // 输出:你好张三,年龄25
}, 2000, '张三', 25);
// 停止延时任务
function stopMyTimeout() {
clearTimeout(timer1);
console.log('延时任务已停止');
}
</script>
</body>
</html>
2. setInterval():周期性重复执行
setInterval() 会每隔一段时间执行一次,直到你手动清掉它。
语法:
let intervalId = setInterval(callback, delay, param1, param2, ...);
参数含义和 setTimeout() 基本一致,区别只在于回调会重复触发。
示例代码:
<!DOCTYPE html>
<html>
<body>
<p>倒计时:<span>10</span> 秒</p>
<button onclick="stopMyInterval()">停止倒计时</button>
<script>
let count = 10;
const countSpan = document.getElementById('count');
// 示例:每秒执行一次倒计时
const intervalId = setInterval(() => {
count--;
countSpan.textContent = count;
if (count <= 0) {
clearInterval(intervalId);
alert('倒计时结束!');
}
}, 1000);
// 手动停止周期性任务
function stopMyInterval() {
clearInterval(intervalId);
countSpan.textContent = '已停止';
}
</script>
</body>
</html>
二、关键注意事项
1. 定时器不是绝对准时
JavaScript 是单线程,定时器里的 delay 只是'最早多久后可以执行',不是精确到点就跑。主线程忙的时候,比如碰上复杂计算,定时器只能等它空下来。
// 看似 1 秒后执行,但实际会等 5 秒(因为 alert 阻塞了主线程)
setTimeout(() => {
console.log('1秒到了?');
}, 1000);
// 阻塞主线程 5 秒
alert('请等待5秒后关闭');
2. 记得清除定时器
页面卸载前或者组件销毁前,没必要继续跑的定时器最好清掉。否则就是白白占着资源,有时还会留下奇怪的副作用。
清除定时器的前提是先保存 timerId,匿名写法后面没法收拾。
// 错误:timerId 是匿名的,无法清除
setTimeout(() => {}, 1000);
// 正确:保存 timerId
const timerId = setTimeout(() => {}, 1000);
clearTimeout(timerId);
setTimeout 适合一次性的延时任务,停止它用 clearTimeout(timerId);setInterval 适合轮询和倒计时,停止它用 clearInterval(intervalId)。它们都不是精确计时,delay 只是最小等待时间。


