JavaScript BOM 核心:window、location、navigator 全攻略
(本教程基于 JavaScript,而非 Python。BOM 是浏览器对象模型,与 Python 无直接关联,请注意辨别。)
🎯 开场 3 分钟:为什么你的网页能"记住"你的浏览器?
你有没有想过这些问题:
- 打开新页面:为什么地址栏的网址会变?网页怎么知道你要去哪?
- 浏览器信息:某些网站怎么知道你用的是 Chrome 还是 Safari?甚至能知道你在用手机还是电脑?
- 页面跳转:点击链接时,浏览器怎么知道要清空旧页面、加载新页面?
如果你做过网页开发,肯定被这些问题困扰过。
这一章要解决的就是:浏览器底层到底是怎么运作的?JavaScript 是怎么和浏览器"对话"的?
学完本文,你能:
- 用代码控制浏览器地址栏的跳转
- 获取用户的浏览器信息,做个性化判断
- 用 history API 实现"假跳转"(不刷新页面的前进后退)
🧱 基础 25 分钟:BOM \n\n
\n\n
\n\n核心概念详解
BOM 是什么?
BOM = Browser Object Model(浏览器对象模型)
你可以把浏览器想象成一栋大楼:
- window = 这栋楼本身(大楼的大门、保安、前台都在这)
- location = 大楼里的门牌号/地址牌(告诉你在哪要去哪)
- navigator = 大楼里的来访登记系统(记录是谁来了、用什么方式来的)
JavaScript 通过 BOM 的这几个对象,就能和浏览器对话。
1. window 对象:浏览器的大管家
window 是 BOM 的核心,它代表整个浏览器窗口。
生活类比:想象 window 是小区的物业中心。物业中心管着:
- 小区的大门(控制进出)
- 小区的广播系统(弹窗提示)
- 小区的监控(定时器)
// 浏览器窗口的宽度和高度
console.log("窗口宽度:", window.innerWidth);
console.log("窗口高度:", window.innerHeight);
// 屏幕的宽度和高度(可能包含任务栏)
console.log("屏幕宽度:", screen.width);
console.log("屏幕高度:", screen.height);
// 浏览器滚动条滚动了多少像素
console.log("滚动Y距离:", window.scrollY);
// 弹出一个提示框(浏览器原生)
window.alert("Hello! 我是 window 的 alert 方法");
运行后,你会看到:
窗口宽度: 1024
窗口高度: 768
屏幕宽度: 1920
屏幕高度: 1080
滚动Y距离: 0
[弹出提示框]
window.alert() 这个方法你肯定见过,网页突然弹出一个"确定"对话框——就是 window 在干活。
2. location 对象:浏览器的地址牌
location 对象代表当前页面的 URL 信息,你可以读取它,也可以修改它来跳转到新页面。
生活类比:location 像酒店的房卡系统。房卡上写着"808房间",你刷卡就能进808。location 就是那个记录着当前"房间号"的东西,而且你还能换房卡去别的房间。
// 获取当前页面的完整 URL
console.log("完整网址:", location.href);
// 获取协议(http:// 或 https://)
console.log("协议:", location.protocol);
// 获取域名(不含路径)
console.log("域名:", location.hostname);
// 获取端口号(通常是 80 或 443)
console.log("端口:", location.port);
// 获取路径(如 /index.html)
console.log("路径:", location.pathname);
// 获取查询参数(?后面的部分,如 ?id=1&name=Tom)
console.log("查询参数:", location.search);
// 跳转到新页面(相当于在地址栏输入新网址并回车)
// location.href = "https://www.example.com";
// 刷新当前页面
// location.reload();
假设当前 URL 是 https://www.example.com:8080/index.html?id=1&name=Tom
运行后会看到:
完整网址: https://www.example.com:8080/index.html?id=1&name=Tom
协议: https:
域名: www.example.com
端口: 8080
路径: /index.html
查询参数: ?id=1&name=Tom
用代码跳转页面的方式:
// 方式1:直接赋值(最常用)
location.href = "https://www.baidu.com";
// 方式2:assign() 方法(效果相同,但语义更明确)
location.assign("https://www.baidu.com");
// 方式3:replace() 方法(不记录浏览历史,无法后退)
// location.replace("https://www.baidu.com");
区别:assign() 会记录浏览历史,可以点"后退";replace() 不记录,相当于"覆盖"。
3. history 对象:浏览器的"前进后退"记录
history 对象让你可以操作浏览器的前进后退功能。
生活类比:history 像手机里的最近通话记录。你可以:
- 往上滑看之前的记录(后退)
- 往下滑看新的记录(前进)
- 直接跳到某一条记录
// 获取历史记录数量
console.log("历史记录数:", history.length);
// 后退一页(相当于点浏览器左上角的后退箭头)
// history.back();
// 前进一页(相当于点前进箭头)
// history.forward();
// 跳转到指定数量的页面(负数=后退,正数=前进)
// history.go(-2); // 后退2页
// history.go(1); // 前进1页
4. navigator 对象:浏览器的心跳监测
navigator 对象告诉你用户用什么浏览器、什么设备来的。
生活类比:navigator 像机场的安检闸机。闸机扫描你的护照(userAgent),就知道你从哪来的、是哪国人。navigator 就是扫描"浏览器护照"的工具。
// 获取浏览器名称和版本
console.log("用户代理:", navigator.userAgent);
// 获取浏览器名称(不是所有浏览器都准确)
console.log("浏览器名称:", navigator.appName);
// 获取浏览器版本
console.log("浏览器版本:", navigator.appVersion);
// 获取操作系统
console.log("操作系统:", navigator.platform);
// 获取语言设置
console.log("语言:", navigator.language);
// 是否联网(现代浏览器可能不准确)
console.log("是否联网:", navigator.onLine);
运行结果示例(Chrome 浏览器):
用户代理: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36
浏览器名称: Netscape
浏览器版本: 5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36
操作系统: MacIntel
语言: zh-CN
是否联网: true
注意:
navigator.appName返回的是 "Netscape"(历史原因),不太准确。所以判断浏览器通常靠navigator.userAgent。
5. screen 对象:屏幕的信息
screen 对象包含用户屏幕的信息:
console.log("屏幕宽度:", screen.width);
console.log("屏幕高度:", screen.height);
console.log("可用宽度(排除任务栏):", screen.availWidth);
console.log("可用高度(排除任务栏):", screen.availHeight);
console.log("颜色深度:", screen.colorDepth);
🔥 实战 35 分钟:3 个递进小项目
项目 1(5 分钟):浏览器信息展示器
功能:把用户的浏览器信息展示在页面上。
// 获取各种浏览器信息
const browserInfo = {
userAgent: navigator.userAgent,
language: navigator.language,
platform: navigator.platform,
onLine: navigator.onLine,
screenWidth: screen.width,
screenHeight: screen.height,
windowWidth: window.innerWidth,
windowHeight: window.innerHeight
};
console.log("=== 你的浏览器信息 ===");
for (const key in browserInfo) {
console.log(key + ": " + browserInfo[key]);
}
预期输出:
=== 你的浏览器信息 ===
userAgent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36
language: zh-CN
platform: MacIntel
onLine: true
screenWidth: 1920
screenHeight: 1080
windowWidth: 1024
windowHeight: 768
一句话解释:用 navigator 和 screen 把用户的"浏览器护照"信息全部读取出来。
项目 2(15 分钟):URL 参数解析器
功能:解析当前 URL 的参数,提取出关键信息。
场景:假设你在做一个天气查询页面,URL 是 weather.html?city=beijing&date=2024-01-15
// 假设当前 URL 是:weather.html?city=beijing&date=2024-01-15&type=cloudy
// 1. 获取查询参数字符串(?后面的部分)
const searchParams = location.search.slice(1); // 去掉开头的 ?
console.log("原始查询字符串:", location.search);
// 2. 解析成对象
function parseQueryString(queryString) {
const result = {};
const pairs = queryString.split('&');
for (const pair of pairs) {
const [key, value] = pair.split('=');
result[decodeURIComponent(key)] = decodeURIComponent(value || '');
}
return result;
}
const params = parseQueryString(searchParams);
console.log("解析后的参数对象:", params);
// 3. 使用这些参数
console.log("查询城市:", params.city);
console.log("查询日期:", params.date);
console.log("天气类型:", params.type);
预期输出:
原始查询字符串: ?city=beijing&date=2024-01-15&type=cloudy
解析后的参数对象: { city: 'beijing', date: '2024-01-15', type: 'cloudy' }
查询城市: beijing
查询日期: 2024-01-15
天气类型: cloudy
一句话解释:把 URL 里"?"后面的参数解析成 JavaScript 对象,方便后续使用。
项目 3(15 分钟):单页面应用的"假跳转"效果
功能:不刷新页面,只用 JavaScript 切换内容,模拟多页面效果。
场景:做一个简单的 tab 切换,点击"首页"、"关于"、"联系"不会真的跳转页面。
// 当前"页面"状态
let currentPage = 'home';
// 页面内容
const pages = {
home: '<h1>欢迎来到首页</h1><p>这是首页内容</p>',
about: '<h1>关于我们</h1><p>我们是一家有趣的公司</p>',
contact: '<h1>联系我们</h1><p>邮箱: hi@example.com</p>'
};
// 切换页面的函数
function switchPage(pageName) {
if (!pages[pageName]) {
console.error("页面不存在:", pageName);
return;
}
currentPage = pageName;
// 更新 URL(不刷新页面)
const newUrl = location.pathname + '?page=' + pageName;
history.pushState({ page: pageName }, '', newUrl);
// 更新页面内容(这里用 console.log 模拟,实际会更新 DOM)
console.log("当前页面:", pageName);
console.log("页面内容:", pages[pageName]);
console.log("浏览器地址栏已更新为:", location.href);
}
// 监听浏览器前进后退按钮
window.addEventListener('popstate', function(event) {
if (event.state && event.state.page) {
currentPage = event.state.page;
console.log("通过前进后退切换到:", currentPage);
console.log("页面内容:", pages[currentPage]);
}
});
// 测试:切换页面
console.log("=== 初始状态 ===");
switchPage('home');
console.log("\n=== 点击"关于"链接 ===");
switchPage('about');
console.log("\n=== 点击"联系"链接 ===");
switchPage('contact');
console.log("\n=== 点击浏览器后退按钮 ===");
// 在浏览器中点击后退会触发 popstate 事件
// 这里模拟一下
history.back();
预期输出:
=== 初始状态 ===
当前页面: home
页面内容: <h1>欢迎来到首页</h1><p>这是首页内容</p>
浏览器地址栏已更新为: /index.html?page=home
=== 点击"关于"链接 ===
当前页面: about
页面内容: <h1>关于我们</h1><p>我们是一家有趣的公司</p>
浏览器地址栏已更新为: /index.html?page=about
=== 点击"联系"链接 ===
当前页面: contact
页面内容: <h1>联系我们</h1><p>邮箱: hi@example.com</p>
浏览器地址栏已更新为: /index.html?page=contact
=== 点击浏览器后退按钮 ===
当前页面: about
页面内容: <h1>关于我们</h1><p>我们是一家有趣的公司</p>
一句话解释:用 history.pushState() 更新 URL 但不刷新页面,配合 popstate 事件监听前进后退,实现单页面应用(SPA)的效果。
💪 进阶 20 分钟:常见坑 + 调试技巧
坑 1:history.back() 没反应?
❌ 错误写法:
// 如果用户没有上一页,back() 会静默失败
history.back();
✅ 正确写法:
// 先检查有没有历史记录
if (history.length > 1) {
history.back();
} else {
console.log("没有上一页了");
}
解释:如果用户是直接输入 URL 进来的,没有任何浏览历史,history.back() 什么都不会做。
坑 2:location.href 赋值后代码继续执行
❌ 错误理解:
location.href = "https://www.example.com";
console.log("这行会执行吗?"); // 会的!
✅ 正确理解:
location.href = "https://www.example.com";
console.log("这行会执行,页面跳转是异步的");
console.log("当前页面还在,不会立即消失");
解释:location.href 赋值后,JavaScript 还会继续执行后面的代码。页面跳转是浏览器的行为,不会阻塞 JS。
坑 3:navigator.onLine 不一定准
❌ 错误依赖:
if (navigator.onLine) {
// 以为用户真的联网了
loadData();
}
✅ 正确做法:
// 实际发一个请求来验证网络
async function checkNetwork() {
try {
const response = await fetch('/api/health', {
method: 'HEAD',
cache: 'no-cache'
});
return response.ok;
} catch {
return false;
}
}
解释:navigator.onLine 只是检测"本机是否联网",不保证能访问具体网站。
坑 4:pushState 不触发 popstate
❌ 错误理解:
history.pushState({}, '', '/new-page');
// 以为会触发 popstate 事件?
// 不会的!pushState 不会触发 popstate,只有前进后退才会。
✅ 正确理解:
// pushState 只是更新 URL 和历史记录栈
history.pushState({ page: 'new' }, '', '/new-page');
// 前进或后退时才会触发 popstate
window.addEventListener('popstate', function(e) {
console.log('状态变了:', e.state);
});
坑 5:decodeURIComponent 要处理异常
❌ 简单写法:
const value = decodeURIComponent(params[name]);
✅ 健壮写法:
function safeDecode(str) {
try {
return decodeURIComponent(str);
} catch {
return str; // 解码失败就返回原字符串
}
}
调试技巧:打印完整的 BOM 信息
// 一行命令看遍所有 BOM 核心信息
console.log('=== BOM 完整诊断 ===', {
window: {
innerWidth: window.innerWidth,
innerHeight: window.innerHeight,
scrollY: window.scrollY
},
location: {
href: location.href,
protocol: location.protocol,
hostname: location.hostname,
pathname: location.pathname,
search: location.search
},
navigator: {
userAgent: navigator.userAgent,
language: navigator.language,
platform: navigator.platform,
onLine: navigator.onLine
},
history: {
length: history.length
},
screen: {
width: screen.width,
height: screen.height
}
});
把这段代码粘贴到浏览器控制台,一眼看穿浏览器状态。
✏️ 练习题
练习 1(2 分钟):获取屏幕信息
- 输入:运行
screen.width和screen.height - 预期输出:显示你屏幕的宽度和高度(如
1920 1080) - 提示:直接打开浏览器控制台输入即可
练习 2(2 分钟):判断是否移动端
- 输入:用
navigator.userAgent判断是否手机访问 - 预期输出:如果是手机显示 "移动端",否则显示 "PC端"
- 提示:userAgent 里会包含 "Mobile" 字样
// 参考答案
const isMobile = /Mobile|Android|iPhone|iPad/i.test(navigator.userAgent);
console.log(isMobile ? "移动端" : "PC端");
练习 3(3 分钟):修改 URL 参数
- 输入:当前 URL 是
test.html?id=1,用代码把 id 改成 2 - 预期输出:地址栏变成
test.html?id=2 - 提示:用
location.search获取参数,修改后用history.pushState更新
练习 4(4 分钟):封装 URL 参数函数
- 输入:解析
name=张三&age=18&city=北京 - 预期输出:对象
{ name: '张三', age: '18', city: '北京' } - 提示:先 split('&'),再 split('='),最后 decodeURIComponent
练习 5(5 分钟):分析报错
- 输入:以下代码报错 "Cannot read property 'href' of undefined"
- 代码:
function goTo(url) {
window.location = url; // 这行报错
}
goTo("https://example.com");
- 预期输出:修复代码,让它能正确跳转
- 提示:应该是
location.href,不是window.location
作业:做一个「浏览器信息面板」
需求描述:做一个网页,显示用户的完整浏览器信息,并在用户点击按钮时能跳转到指定页面或刷新。
功能点:
1. 页面加载时自动显示:屏幕分辨率、窗口大小、浏览器语言、是否移动端、当前 URL
2. 输入一个网址,点击按钮跳转到该网址
3. 有一个「刷新页面」按钮,点击后刷新当前页
4. 显示浏览历史记录数量
加分项:
1. 用 pushState 实现"假跳转",不刷新页面只更新 URL
2. 监听 popstate 事件,实现前进后退时更新显示内容
验收标准:
- 能跑起来(复制到 .html 文件用浏览器打开)
- 所有信息正确显示
- 跳转功能可用
📚 总结 + 资源
本文学到的 3 个核心点:
1. window 是 BOM 的核心,代表整个浏览器窗口
2. location 管理 URL 信息,可以读取和修改地址栏
3. navigator 提供浏览器和用户环境的信息
延伸学习资源:
- MDN Web Docs - BOM 官方文档(最权威的参考)
- 《JavaScript 高级程序设计》第 22 章 - BOM 深度讲解
- MDN - History API 指南
互动钩子:你在做网页时有没有被"浏览器跳转"坑过?比如点击后退按钮页面没反应、或者想刷新但用户数据丢了?评论区聊聊,老粉优先回复!
下章预告:学完了 BOM,你已经掌握了浏览器和 JavaScript 交互的核心能力。下一章我们要做一个天气查询的单页面应用,把所有这些知识串起来用——用 Fetch API 获取数据、用 BOM 控制跳转、用 history.pushState 实现"假刷新"……敬请期待!

评论(0)