说说你对BOM的理解?
问题解析
BOM(Browser Object Model,浏览器对象模型)是 JavaScript 中与浏览器进行交互的一套 API。它提供了独立于页面内容的、与浏览器窗口进行交互的对象,使开发者能够控制浏览器的行为、获取浏览器信息、操作浏览器窗口等。
核心概念
BOM 与 DOM 的区别
| 特性 | BOM | DOM |
|---|---|---|
| 全称 | Browser Object Model | Document Object Model |
| 操作对象 | 浏览器窗口 | HTML/XML 文档 |
| 核心对象 | window | document |
| 标准化 | 无统一标准(各浏览器实现略有差异) | W3C 标准 |
| 内容 | 窗口控制、导航、屏幕信息等 | 文档结构、元素操作 |
关系:BOM 包含 DOM,DOM 是 BOM 的一部分。
window (BOM 核心)
├── document (DOM)
├── location
├── navigator
├── screen
├── history
└── frames
详细解答
一、window 对象
window 是 BOM 的核心对象,它代表浏览器的一个实例,也是 JavaScript 的全局对象。
1. 全局作用域
// 在全局作用域声明的变量和函数都会成为 window 的属性和方法
var name = 'JavaScript';
function sayName() {
console.log(this.name);
}
console.log(window.name); // "JavaScript"
window.sayName(); // "JavaScript"
// 注意:let 和 const 声明的变量不会成为 window 的属性
let age = 25;
const PI = 3.14;
console.log(window.age); // undefined
console.log(window.PI); // undefined
2. 窗口控制方法
// 移动窗口(部分浏览器限制)
window.moveBy(100, 100); // 相对当前位置移动(水平,垂直)
window.moveTo(100, 100); // 移动到指定位置
// 调整窗口大小(部分浏览器限制)
window.resizeBy(200, 200); // 相对当前大小调整
window.resizeTo(800, 600); // 调整到指定大小
// 滚动窗口
window.scrollTo(0, 500); // 滚动到指定位置
window.scrollBy(0, 100); // 相对当前位置滚动
// 平滑滚动
window.scrollTo({
top: 500,
behavior: 'smooth'
});
3. 窗口打开与关闭
// 打开新窗口
const newWindow = window.open(
'https://www.example.com', // URL
'myWindow', // 窗口名称(用于 target 属性)
'width=800,height=600,left=100,top=100,resizable=yes'
);
// 窗口特性参数
// width/height: 窗口宽高
// left/top: 窗口位置
// resizable: 是否可调整大小
// scrollbars: 是否显示滚动条
// status: 是否显示状态栏
// 关闭窗口
newWindow.close();
// 检查窗口是否关闭
console.log(newWindow.closed); // true 或 false
// 获取打开当前窗口的窗口引用
console.log(window.opener); // 如果有父窗口则返回引用
4. 定时器
// setTimeout - 延迟执行(一次)
const timeoutId = setTimeout(() => {
console.log('3秒后执行');
}, 3000);
// 取消定时器
clearTimeout(timeoutId);
// setInterval - 间隔执行(重复)
const intervalId = setInterval(() => {
console.log('每2秒执行一次');
}, 2000);
// 取消定时器
clearInterval(intervalId);
// requestAnimationFrame - 浏览器重绘前执行(动画推荐)
function animate() {
// 执行动画
console.log('动画帧');
requestAnimationFrame(animate);
}
const rafId = requestAnimationFrame(animate);
cancelAnimationFrame(rafId);
5. 系统对话框
// 警告框
window.alert('这是一个警告');
// 确认框
const isConfirmed = window.confirm('确定要删除吗?');
console.log(isConfirmed); // true(确定)或 false(取消)
// 输入框
const userInput = window.prompt('请输入您的名字', '默认值');
console.log(userInput); // 用户输入的内容,取消则返回 null
// 打印对话框
window.print();
// 查找对话框
window.find('search text');
二、location 对象
location 对象提供了当前窗口中加载文档的信息,以及导航功能。
// 完整 URL:http://www.example.com:8080/path/page.html?q=1#section
console.log(location.href); // 完整 URL
console.log(location.protocol); // "http:"
console.log(location.host); // "www.example.com:8080"
console.log(location.hostname); // "www.example.com"
console.log(location.port); // "8080"
console.log(location.pathname); // "/path/page.html"
console.log(location.search); // "?q=1"
console.log(location.hash); // "#section"
console.log(location.origin); // "http://www.example.com:8080"
导航方法
// 跳转到新页面(会在浏览器历史中添加记录)
location.href = 'https://www.example.com';
// 或
location.assign('https://www.example.com');
// 替换当前页面(不会在历史中添加记录)
location.replace('https://www.example.com');
// 重新加载页面
location.reload(); // 从缓存加载
location.reload(true); // 从服务器重新加载
// 解析 URL 查询参数
function getQueryParam(name) {
const params = new URLSearchParams(location.search);
return params.get(name);
}
console.log(getQueryParam('q'));
三、navigator 对象
navigator 对象包含了浏览器的信息,常用于检测浏览器类型、版本,以及获取用户设备信息。
// 浏览器信息
console.log(navigator.userAgent); // 用户代理字符串
console.log(navigator.appName); // 浏览器名称
console.log(navigator.appVersion); // 浏览器版本
console.log(navigator.platform); // 操作系统平台
// 语言
console.log(navigator.language); // 首选语言
console.log(navigator.languages); // 语言列表
// 网络状态
console.log(navigator.onLine); // 是否在线
// 监听网络状态变化
window.addEventListener('online', () => {
console.log('网络已连接');
});
window.addEventListener('offline', () => {
console.log('网络已断开');
});
// 地理位置
navigator.geolocation.getCurrentPosition(
position => {
console.log('纬度:', position.coords.latitude);
console.log('经度:', position.coords.longitude);
},
error => {
console.error('获取位置失败:', error);
}
);
// 剪贴板 API
navigator.clipboard.writeText('复制的内容')
.then(() => console.log('已复制到剪贴板'));
navigator.clipboard.readText()
.then(text => console.log('剪贴板内容:', text));
// 媒体设备(摄像头、麦克风)
navigator.mediaDevices.getUserMedia({ video: true, audio: true })
.then(stream => {
// 使用媒体流
});
// 电池状态(部分浏览器支持)
navigator.getBattery().then(battery => {
console.log('电量:', battery.level * 100 + '%');
console.log('是否充电:', battery.charging);
});
// 分享功能(Web Share API)
navigator.share({
title: '分享标题',
text: '分享内容',
url: 'https://www.example.com'
});
四、screen 对象
screen 对象包含了客户端显示器的信息。
// 屏幕尺寸
console.log(screen.width); // 屏幕宽度
console.log(screen.height); // 屏幕高度
console.log(screen.availWidth); // 可用宽度(除去任务栏等)
console.log(screen.availHeight); // 可用高度
// 颜色深度
console.log(screen.colorDepth); // 颜色位数(如 24)
console.log(screen.pixelDepth); // 像素深度
// 屏幕方向
console.log(screen.orientation);
// 监听方向变化
screen.orientation.addEventListener('change', () => {
console.log('屏幕方向改变:', screen.orientation.type);
});
五、history 对象
history 对象用于操作浏览器的会话历史(即访问过的页面)。
// 历史记录数量
console.log(history.length);
// 前进/后退
history.back(); // 后退一页(等同于点击后退按钮)
history.forward(); // 前进一页
history.go(-1); // 后退一页
history.go(1); // 前进一页
history.go(0); // 刷新当前页
// HTML5 History API
// 添加历史记录(不刷新页面)
history.pushState(
{ page: 1 }, // state 对象
'Page Title', // 标题(大部分浏览器忽略)
'/new-path' // URL(必须同源)
);
// 替换当前历史记录
history.replaceState(
{ page: 2 },
'New Title',
'/another-path'
);
// 监听历史记录变化
window.addEventListener('popstate', event => {
console.log('历史记录变化:', event.state);
});
单页应用(SPA)路由实现
// 简单的路由系统
class Router {
constructor() {
this.routes = {};
window.addEventListener('popstate', this.handlePopState.bind(this));
}
route(path, handler) {
this.routes[path] = handler;
}
navigate(path) {
history.pushState({ path }, '', path);
this.handleRoute(path);
}
handlePopState(event) {
const path = location.pathname;
this.handleRoute(path);
}
handleRoute(path) {
const handler = this.routes[path];
if (handler) {
handler();
}
}
}
// 使用
const router = new Router();
router.route('/', () => console.log('首页'));
router.route('/about', () => console.log('关于页面'));
// 导航
document.getElementById('about-link').addEventListener('click', () => {
router.navigate('/about');
});
深入理解
浏览器检测
// 检测浏览器类型
function detectBrowser() {
const ua = navigator.userAgent;
if (ua.indexOf('Chrome') > -1 && ua.indexOf('Edg') === -1) {
return 'Chrome';
} else if (ua.indexOf('Safari') > -1 && ua.indexOf('Chrome') === -1) {
return 'Safari';
} else if (ua.indexOf('Firefox') > -1) {
return 'Firefox';
} else if (ua.indexOf('Edg') > -1) {
return 'Edge';
} else if (ua.indexOf('Opera') > -1 || ua.indexOf('OPR') > -1) {
return 'Opera';
}
return 'Unknown';
}
// 检测移动设备
function isMobile() {
return /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent);
}
// 检测特性支持(更推荐的方式)
if ('geolocation' in navigator) {
// 支持地理位置
}
if ('serviceWorker' in navigator) {
// 支持 Service Worker
}
跨窗口通信
// 同源窗口间通信
const popup = window.open('https://same-origin.com/page.html', 'popup');
// 发送消息
popup.postMessage('Hello from parent', 'https://same-origin.com');
// 接收消息
window.addEventListener('message', event => {
// 验证来源
if (event.origin !== 'https://same-origin.com') return;
console.log('收到消息:', event.data);
console.log('来源:', event.origin);
console.log('源窗口:', event.source);
});
最佳实践
-
避免使用浏览器检测,优先使用特性检测
// ❌ 不推荐 if (navigator.userAgent.indexOf('Chrome') > -1) { // Chrome 特有功能 } // ✅ 推荐 if ('geolocation' in navigator) { // 使用地理位置 } -
使用 History API 实现 SPA 时,要处理服务器端配置
-
使用 window.open 时要注意弹窗拦截
// 在用户交互回调中打开窗口,避免被拦截 button.addEventListener('click', () => { window.open('https://example.com', '_blank'); }); -
清理定时器,避免内存泄漏
const timer = setTimeout(() => {}, 1000); // 组件卸载时清理 clearTimeout(timer); -
使用 URLSearchParams 处理查询参数
const params = new URLSearchParams(location.search); const value = params.get('key');
面试要点
-
什么是 BOM?
- Browser Object Model,浏览器对象模型
- 提供与浏览器窗口交互的 API
- 核心对象是 window
-
BOM 和 DOM 的区别?
- BOM 操作浏览器窗口,DOM 操作文档内容
- BOM 没有统一标准,DOM 是 W3C 标准
- BOM 包含 DOM(window.document)
-
window 对象的常用方法?
- 窗口控制:open、close、moveTo、resizeTo
- 定时器:setTimeout、setInterval、requestAnimationFrame
- 对话框:alert、confirm、prompt
- 滚动:scrollTo、scrollBy
-
location 和 history 对象的作用?
- location:获取/设置 URL,页面导航
- history:操作浏览器历史记录,实现前进/后退/SPA 路由
-
navigator 对象可以获取哪些信息?
- 浏览器类型和版本(userAgent)
- 操作系统平台
- 网络状态(onLine)
- 地理位置
- 各种现代 API(剪贴板、媒体设备、电池等)
-
如何实现单页应用(SPA)的路由?
- 使用 history.pushState/replaceState 改变 URL 不刷新页面
- 监听 popstate 事件处理前进/后退
- 根据 URL 路径渲染对应组件