JavaScript BOM 核心:window、location、navigator 全攻略

(本教程基于 JavaScript,而非 Python。BOM 是浏览器对象模型,与 Python 无直接关联,请注意辨别。)


🎯 开场 3 分钟:为什么你的网页能"记住"你的浏览器?

你有没有想过这些问题:

  • 打开新页面:为什么地址栏的网址会变?网页怎么知道你要去哪?
  • 浏览器信息:某些网站怎么知道你用的是 Chrome 还是 Safari?甚至能知道你在用手机还是电脑?
  • 页面跳转:点击链接时,浏览器怎么知道要清空旧页面、加载新页面?

如果你做过网页开发,肯定被这些问题困扰过。

这一章要解决的就是:浏览器底层到底是怎么运作的?JavaScript 是怎么和浏览器"对话"的?

学完本文,你能:
- 用代码控制浏览器地址栏的跳转
- 获取用户的浏览器信息,做个性化判断
- 用 history API 实现"假跳转"(不刷新页面的前进后退)


🧱 基础 25 分钟:BOM \n\nSimple tech illustration expla\n\nAI comic creation scene, creat\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

一句话解释:用 navigatorscreen 把用户的"浏览器护照"信息全部读取出来。


项目 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.widthscreen.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 实现"假刷新"……敬请期待!

声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。