JavaScript BOM(浏览器对象模型)
BOM(Browser Object Model)是浏览器暴露给 JS 的一组对象,让我们能控制浏览器本身:窗口、地址栏、历史记录、屏幕、剪贴板。如果说 DOM 操作的是"网页内容",BOM 操作的就是"浏览器外壳"。这一章我们学习 BOM 的核心对象。
1. window:顶层对象
window 是浏览器 JS 的全局对象——所有全局变量、内置函数都是它的属性。前面用过的 alert、console、document 都是 window 的属性,只是平时省略不写。
// window 是浏览器的顶层对象,所有全局变量都是它的属性
console.log(window.innerWidth); // 视口宽度(像素)
console.log(window.innerHeight); // 视口高度
console.log(window.devicePixelRatio); // 设备像素比(高分屏 = 2 或 3)
// 窗口尺寸
window.resizeTo(800, 600); // 调整窗口大小(会被弹窗拦截)
// 弹窗(不推荐用于产品,只用调试)
alert("提示");
confirm("确定要删除吗?"); // 返回 true / false
prompt("请输入姓名:"); // 返回输入值或 null
// 滚动
window.scrollTo(0, 500); // 滚到指定位置
window.scrollTo({ top: 500, behavior: "smooth" }); // 平滑滚动
window.scrollBy(0, 100); // 相对滚动 100px
// 全局变量 = window 属性
var x = 1;
console.log(window.x); // 1(var 会成为 window 属性)
let y = 2;
console.log(window.y); // undefined(let 不会)实际开发中 window 通常省略(如直接写 alert),只在需要消歧义或访问 window 自身属性时显式写出。
2. location:URL 与跳转
location 是页面 URL 的"遥控器",既能读取 URL 各部分,也能跳转页面:
// location:当前页面 URL 信息
console.log(location.href); // 完整 URL
console.log(location.protocol); // "https:"
console.log(location.host); // "example.com:8080"
console.log(location.hostname); // "example.com"
console.log(location.port); // "8080"
console.log(location.pathname); // "/page/article"
console.log(location.search); // "?id=1&name=x"
console.log(location.hash); // "#section-1"(锚点)
// 跳转页面
location.href = "https://example.com"; // 跳转(留历史记录)
location.replace("https://example.com"); // 跳转(不留历史,不能后退)
location.reload(); // 刷新页面
// 修改 URL 参数(添加参数不刷新)
const url = new URL(location.href);
url.searchParams.set("page", "2");
url.searchParams.get("page"); // "2"
history.pushState({}, "", url); // 改 URL 不刷新(SPA 路由原理)URL 对象(new URL())是处理 URL 参数的现代方式,比手动 split 字符串可靠得多。配合 history.pushState 实现 SPA 路由的核心原理。
3. history:前进后退
// history:浏览器历史记录
history.back(); // 后退
history.forward(); // 前进
history.go(-2); // 后退 2 步
history.go(1); // 前进 1 步
// SPA 路由:不刷新页面,改 URL
history.pushState({ page: 1 }, "", "/list");
history.pushState({ page: 2 }, "", "/list/2");
// 监听前进/后退(浏览器按钮或 history.go)
window.addEventListener("popstate", (e) => {
console.log("URL 变了:", location.pathname);
console.log("状态:", e.state);
});
// replaceState:替换当前记录(不留新历史)
history.replaceState({ page: 1 }, "", "/home");History API 是单页应用(SPA)的基石。React Router、Vue Router 等"前端路由"库,底层就是 pushState + popstate 监听——不刷新页面改 URL,响应用户的前进后退按钮。
4. 定时器
setTimeout 和 setInterval 是 JS 里安排"未来执行代码"的方式:
// setTimeout:延迟执行一次
const timer1 = setTimeout(() => {
console.log("3 秒后执行");
}, 3000);
// 取消
clearTimeout(timer1);
// setInterval:重复执行
const timer2 = setInterval(() => {
console.log("每 1 秒执行");
}, 1000);
// 取消
clearInterval(timer2);
// 实战:倒计时
let count = 10;
const timer = setInterval(() => {
console.log(count);
count--;
if (count < 0) {
clearInterval(timer); // 别忘了清,否则一直跑
console.log("结束!");
}
}, 1000);
// ⚠️ 计时器不精确!最小延迟 ~4ms,后台标签页会被节流到 1000ms
// 需要精确计时用 performance.now() + requestAnimationFrame记忆口诀:
setTimeout:一次定时,延迟执行。setInterval:重复定时,周期执行。
定时器的坑:JS 是单线程的,定时器只是"在主线程空闲时尽快执行",不是精确时间。后台标签页会被浏览器节流到 1s,手机省电模式更慢。需要精确动画用 requestAnimationFrame,需要精确计时用 performance.now()。
务必记得 clearInterval:组件销毁时不清定时器,会造成内存泄漏和 bug。React 的 useEffect 必须返回清理函数就是这个原因。
5. localStorage 与 sessionStorage
这是浏览器提供的本地存储,可以让网页在用户关闭后再打开时,仍然记得数据:
// localStorage:永久存储(关闭浏览器也在)
// sessionStorage:会话存储(关闭标签页就清空)
// 两者 API 完全一样,只是生命周期不同
// 存(必须是字符串,对象要先 JSON.stringify)
localStorage.setItem("username", "小明");
localStorage.setItem("user", JSON.stringify({ name: "小明", age: 20 }));
// 取
const name = localStorage.getItem("username"); // "小明"
const user = JSON.parse(localStorage.getItem("user"));
// 删
localStorage.removeItem("username");
// 清空所有
localStorage.clear();
// 遍历所有 key
for (let i = 0; i < localStorage.length; i++) {
const key = localStorage.key(i);
console.log(key, localStorage.getItem(key));
}
// ⚠️ 容量限制(约 5-10MB),同步 API 会阻塞,大用 IndexedDB- localStorage:永久存储,除非主动清除,否则一直保留。用于用户偏好、登录 token 等。
- sessionStorage:会话存储,标签页关闭就清空。用于临时数据。
三个注意点:
- 只能存字符串,对象要先
JSON.stringify。 - 容量约 5-10MB,超过会抛异常,需要 try/catch。
- 不要存敏感信息(密码、token 明文)——XSS 攻击会偷走。需要安全存储用 HttpOnly Cookie。
6. navigator:浏览器与设备
// navigator:浏览器信息
console.log(navigator.userAgent); // 浏览器标识字符串
console.log(navigator.language); // "zh-CN"
console.log(navigator.platform); // "MacIntel" / "Win32"
// 检测是否在线
console.log(navigator.onLine); // true / false
window.addEventListener("online", () => console.log("联网了"));
window.addEventListener("offline", () => console.log("断网了"));
// 剪贴板
navigator.clipboard.writeText("复制的内容").then(() => {
console.log("复制成功");
});
navigator.clipboard.readText().then(text => {
console.log("粘贴板内容:", text);
});
// 地理定位(需要用户授权)
navigator.geolocation.getCurrentPosition(pos => {
console.log(pos.coords.latitude, pos.coords.longitude);
});
// 屏幕
console.log(screen.width); // 屏幕分辨率宽
console.log(screen.height);
console.log(screen.availWidth); // 可用宽度(去除任务栏)navigator.userAgent 可以用来判断浏览器类型(Chrome / Safari / 微信内置浏览器),但现代开发推荐用特性检测(if ('geolocation' in navigator))而不是 UA 嗅探——UA 字符串很容易伪造,且版本繁多。
7. screen 屏幕
console.log(screen.width, screen.height); // 物理分辨率
console.log(screen.availWidth, screen.availHeight); // 可用区域(扣除任务栏)
console.log(screen.colorDepth); // 颜色深度,通常是 24
// 媒体查询(JS 版,响应式必备)
const mq = window.matchMedia("(max-width: 768px)");
console.log(mq.matches); // 视口是否 <= 768px
mq.addEventListener("change", (e) => {
console.log(e.matches ? "切换到手机" : "切换到桌面");
});
// 全屏 API
document.documentElement.requestFullscreen(); // 进入全屏
document.exitFullscreen(); // 退出全屏8. 实战:页面加载完成、滚动监听
// DOM 加载完成(不等图片等资源,推荐)
document.addEventListener("DOMContentLoaded", () => {
console.log("DOM 准备好了,可以操作元素");
});
// 整个页面(含图片)加载完成
window.addEventListener("load", () => {
console.log("所有资源加载完成");
});
// 页面卸载(刷新/关闭)
window.addEventListener("beforeunload", (e) => {
e.preventDefault();
e.returnValue = ""; // 浏览器会弹"确定离开吗?"
});
// 滚动监听(实战:吸顶导航 / 懒加载)
let ticking = false;
window.addEventListener("scroll", () => {
if (!ticking) {
requestAnimationFrame(() => {
console.log(window.scrollY); // 当前滚动位置
ticking = false;
});
ticking = true;
}
});9. 实战:用户偏好记忆
// 进入网站时,读取上次的主题偏好
const saved = localStorage.getItem("theme") || "light";
document.body.classList.toggle("dark", saved === "dark");
// 用户切换主题时,保存
document.querySelector("#themeBtn").addEventListener("click", () => {
const isDark = document.body.classList.toggle("dark");
localStorage.setItem("theme", isDark ? "dark" : "light");
});
// 实战:购物车本地暂存
function saveCart(cart) {
localStorage.setItem("cart", JSON.stringify(cart));
}
function loadCart() {
try {
return JSON.parse(localStorage.getItem("cart")) || [];
} catch {
return []; // 解析失败时给默认值
}
}小结
window是顶层对象,包含一切。location处理 URL,可跳转页面。history控制前进后退,是 SPA 路由的基石。setTimeout/setInterval定时执行,务必记得清理。localStorage永久存储,sessionStorage会话存储。navigator提供浏览器/设备信息。
下一篇我们看 JS 最有特色的异步编程——Promise 与 async/await,这是处理网络请求、定时器、文件 IO 的关键。
← 上一篇 JavaScript 事件
下一篇 JavaScript 异步与 Promise →