- 理解BOM的核心:window对象
- 控制窗口及弹窗
- 通过location对象获取页面信息
- 使用navigator对象了解浏览器
- 通过history对象操作浏览器历史
1. window对象
BOM的核心是window对象 ,表示浏览器的实例。window对象 在浏览器中有两重身份,一个是ECMAScript中的Global对象,另一个是浏览器窗口的JavaScript接口。这意味着网页中定义的所有对象、变量和函数都以window 作为其Global对象,都可以访问其上定义的parseInt()
等全局方法。
注意 因为window对象 的属性在全局作用域中有效,所以很多浏览器API及相关构造函数都以window对象的形式暴露出来。
2. Global 作用域
因为window对象 被复用为ECMAScript的Global对象,所以通过var
声明的所有全局变量和函数都会变成window对象的属性和方法。例如:
js
var age = 29;
var sayAge = () => alert(this.age);
alert(window.age); // 29
sayAge(); // 29
window.sayAge(); // 29
这里,变量 age
和函数 sayAge()
被定义在全局作用域中,它们自动成为 window对象 的成员。因此,变量 age
可以通过 window.age
来访问,而函数 sayAge()
也可以通过 window.sayAge()
来访问。因为 sayAge()
存在于全局作用域,this.age
映射到 window.age
,所以可以显示正确的结果。
如果在这里使用 let
或 const
替代 var
,则不会把变量添加给全局对象:
js
let age = 29;
const sayAge = () => alert(this.age);
alert(window.age); // undefined
sayAge(); // undefined
window.sayAge(); // TypeError: window.sayAge is not a function
另外,访问未声明的变量会抛出错误,但是可以在 window对象 上查询是否存在可能未声明的变量。例如:
js
// 这会导致抛出错误,因为 oldValue 没有声明
var newValue = oldValue;
// 这不会抛出错误,因为这里是属性查询
// newValue 会被设置为 undefined
var newValue = window.oldValue;
记住,JavaScript 中有很多对象暴露在全局作用域中,比如 location 和 navigator (本章后面都会讨论),因它们也是 window对象 的属性。
3. globalThis 属性
取决于在什么环境下运行 JavaScript,全局对象也有几种不同的形式。
- 在网页脚本中,全局对象是 window 、self 或 frames。
- Web Worker 中,全局对象是 self。
- 在 Node.js 中,全局对象是 global。
- 在脚本的顶级,
this
通常引用全局对象,但在严格模式下或在有箭头函数的情况下,问题会复杂一些。
为消除这些差异,ECMAScript 定义了一个 globalThis 属性,以期达成两个目标:
- 将跨环境访问全局
this
的方式统一为 globalThis ,即在网页中 globalThis == window ,在 Web Worker 中 globalThis == self。 - 允许脚本修改和控制 globalThis 的特性和行为,因为 globalThis 是对全局对象的直接引用,其本身是可写、可配置的。
在非浏览器引擎中,globalThis 属性直接引用全局对象,而在浏览器引擎中,它通过代理间接引用全局对象。
在需要访问全局对象且有可能在不一样的 JavaScript 环境中共享的时候,应该使用 globalThis 。如果脚本只在一个环境下运行,应该用不到 globalThis。
4. 窗口关系
top 对象始终指向最上层(最外层)窗口,即浏览器窗口本身。而 parent 对象始终指向当前窗口的父窗口。如果当前窗口是最上层窗口,则 parent 等于 top(都等于 window ,最上层的成员)。如果不是通过 window.open()
打开的,那么其 parent 属性不会包含值,本章后面会介绍。 还有一个 self
对象,它是终极 window
属性,始终会指向 window
。实际上,self
和 window
是同一个对象。之所以还要暴露 self
,就是为了和 top
、parent
保持一致。
这些属性都是 window
对象的属性,因此访问 window.parent
、window.top
和 window.self
都可以。这意味着可以把访问多个窗口的 window
对象串联起来,比如 window.parent.parent
。
5. 窗口位置与像素比
窗口位置
window 对象的位置可以通过不同的属性和方法来确定。现代浏览器提供了 screenLeft
、screenTop
属性,用于表示窗口相对于屏幕左侧和顶部的位置,返回值的单位是 CSS 像素。
可以使用 moveTo()
和 moveBy()
方法移动窗口。moveTo()
接收要移动到的新位置的绝对坐标,而 moveBy()
接收相对当前位置在两个方向上移动的像素数。例如:
javascript
// 把窗口移动到左上角
window.moveTo(0, 0);
// 把窗口向下移动 100 像素
window.moveBy(0, 100);
// 把窗口移动到坐标位置 (200, 300)
window.moveTo(200, 300);
// 把窗口向左移动 50 像素
window.moveBy(-50, 0);
依浏览器而定,以上方法可能会被部分或全部禁用。
像素比
CSS 像素 是 Web 开发中使用的统一像素单位。这个单位的背后其实是一个角度:0.0213° 。屏幕距离人眼是一臂长 ,则以这个角度计算的 CSS 像素 大约为 1/96 英寸 。这样定义像素大小是为了在不同设备上统一标准 。比如,低分辨率平板设备 上 12 像素(CSS 像素) 的文字应该与高分辨率设备 上 12 像素(CSS 像素) 的文字具有相同大小 。这就带来了一个问题,不同像素密度 的屏幕下就会有不同缩放系数 ,以便把物理像素 (屏幕实际的分辨率)转换为 CSS 像素(浏览器报告的虚拟分辨率)。
举个例子,手机屏幕 的物理分辨率 可能是 1920×1080 ,但因为其像素可能非常密集 ,所以浏览器会将其分辨率降为较低的逻辑分辨率 ,比如 640×360 。这个物理像素 与 CSS 像素 之间的转换比率 由 window.devicePixelRatio
属性提供。对于分辨率从 1920×1080 转换为 640×360 的设备,window.devicePixelRatio
的值就是 3 。这样一来,12 像素(CSS 像素) 的文字实际上会用 36 像素 的物理像素来显示。
window.devicePixelRatio
实际上与每英寸像素数(DPI,dots per inch)是对应的。DPI 表示屏幕的像素密度 ,而 window.devicePixelRatio
表示物理像素 与逻辑像素 之间的缩放系数。
6. 窗口大小
在不同浏览器中确定浏览器窗口大小没有想象中那么容易。所有现代浏览器都支持 4 个属性:innerWidth
、innerHeight
、outerWidth
和 outerHeight
。outerWidth
和 outerHeight
返回浏览器窗口自身的大小(不管是在最外层 window
上使用,还是在窗格 <frames>
中使用)。innerWidth
和 innerHeight
返回浏览器窗口中页面视口的大小(不包含浏览器边框和工具栏)。 document.documentElement.clientWidth
和 document.documentElement.clientHeight
返回页面视口的宽度和高度。
在移动设备上,window.innerWidth
和 window.innerHeight
返回视口的大小,也就是屏幕上页面可见区域的大小。在放大或缩小页面时,这些值也会相应变化。document.documentElement
用于度量布局视口的大小,即渲染页面的实际大小。布局视口是相对于可见视口的概念,可见视口只能显示整个页面的一小部分。在放大或缩小页面时,这些值也会相应变化。
因为桌面浏览器的差异,所以需要先确定用户是不是在使用移动设备,然后再决定使用哪个属性。
可以使用 resizeTo()
和 resizeBy()
方法调整窗口大小。这两个方法都接收两个参数 :resizeTo()
接收新的宽度和高度值,而 resizeBy()
接收宽度和高度各缩放多少像素。示例如下:
js
// 缩放到100x100
window.resizeTo(100, 100);
// 缩放到200x150(相对当前尺寸+100宽+50高)
window.resizeBy(100, 50);
// 缩放到300x300
window.resizeTo(300, 300);
与移动窗口的方法一样,缩放窗口的方法可能会被浏览器禁用,而且在某些浏览器中默认是禁用的。同样,缩放窗口的方法只能应用到最上层的 window
对象。
7. 视口位置
浏览器窗口尺寸通常无法完整显示整个页面,用户可通过滚动在有限视口中查看文档。度量文档相对于视口滚动距离的属性有两对,它们返回相等的值 :window.pageXOffset
/window.scrollX
和 window.pageYOffset
/window.scrollY
。
可以使用 scroll()
、scrollTo()
和 scrollBy()
方法滚动页面。这3个方法都接收表示相对视口距离的x和y坐标 ,前两个方法中参数表示要滚动到的坐标,scrollBy()
中表示滚动的距离。示例如下:
js
// 相对于当前视口向下滚动100像素
window.scrollBy(0, 100);
// 相对于当前视口向右滚动40像素
window.scrollBy(40, 0);
// 滚动到页面左上角
window.scrollTo(0, 0);
// 滚动到距离屏幕左边及顶边各100像素的位置
window.scrollTo(100, 100);
这几个方法还接收一个 ScrollToOptions
字典 ,除了提供偏移值,还可以通过 behavior
属性告诉浏览器是否平滑滚动:
js
// 平滑滚动到left:100, top:100的位置
window.scrollTo({
left: 100,
top: 100,
behavior: 'smooth' // 'auto'为默认即时滚动,'smooth'为平滑滚动
});
// 平滑滚动到left:100, top:100的位置
window.scrollTo({
left: 100,
top: 100,
behavior: 'smooth'
});
8. 导航与打开新窗口
window.open()
方法可用于导航到指定 URL 或打开新浏览器窗口。该方法接收4个参数 :要加载的 URL、目标窗口、特性字符串和表示新窗口是否替代当前页面历史记录的布尔值。通常只传前3个参数,最后一个参数仅在不打开新窗口时使用。
如果 window.open()
的第二个参数是已存在的窗口或框架(frame
)的名字,则会在对应窗口/框架中打开 URL。示例:
js
// 与<a href="http://www.wiley.com" target="topFrame"/>相同
window.open("http://www.wiley.com/", "topFrame");
执行效果等同于点击 href="http://www.wiley.com"
且 target="topFrame"
的链接。若存在名为"topFrame"的窗口,则在该窗口打开 URL;否则新建窗口并命名为"topFrame" 。
第二个参数也可使用特殊窗口名 ,如 _self
、_parent
、_top
或 _blank
。
1. 弹出窗口
若 window.open()
的第二个参数不是已存在窗口,则打开新窗口或标签页。第三个参数(特性字符串)用于指定新窗口配置,若未传则使用浏览器默认特性(工具栏、地址栏等);若不打开新窗口则忽略此参数。
特性字符串是逗号分隔的配置项,常用设置如下表:
设置 | 值 | 说明 |
---|---|---|
height |
数值 | 新窗口高度(不能小于100) |
left |
数值 | 新窗口x坐标(不能为负值) |
location |
"yes"/"no" | 是否显示地址栏(不同浏览器默认值不同,设为"no"时可能隐藏或禁用) |
menubar |
"yes"/"no" | 是否显示菜单栏(默认"no") |
resizable |
"yes"/"no" | 是否允许拖动改变窗口大小(默认"no") |
scrollbars |
"yes"/"no" | 内容过长时是否显示滚动条(默认"no") |
status |
"yes"/"no" | 是否显示状态栏(不同浏览器默认值不同) |
toolbar |
"yes"/"no" | 是否显示工具栏(默认"no") |
top |
数值 | 新窗口y坐标(不能为负值) |
width |
数值 | 新窗口宽度(不能小于100) |
注意 :部分选项(如
toolbar
、scrollbars
)在 Firefox 和 Chrome 等现代浏览器中可能不被支持。
window.open()
的特性字符串需以逗号分隔的名值对形式出现(名值对用等号连接,字符串中不能包含空格)。示例:
JavaScript
window.open("http://www.wiley.com/",
"wileyWindow",
"height=400,width=400,top=10,left=10,resizable=yes");
执行效果:打开一个可缩放的新窗口,大小为 400像素×400像素,位于离屏幕左边及顶边各10像素的位置。
window.open()
返回值
window.open()
方法返回一个对新建窗口的引用 (window
对象),可用于控制新窗口。示例:
JavaScript
let wileyWin = window.open("http://www.wiley.com/",
"wileyWindow",
"height=400,width=400,top=10,left=10,resizable=yes");
// 缩放窗口(调整为500x500)
wileyWin.resizeTo(500, 500);
// 移动窗口(左上角坐标(100,100))
wileyWin.moveTo(100, 100);
// 关闭窗口
wileyWin.close();
注意:
close()
方法仅能关闭window.open()
创建的弹出窗口,不能直接关闭主窗口(需用户确认)。- 窗口关闭后,引用仍存在,可通过
closed
属性检查状态:alert(wileyWin.closed); // true
(关闭后返回true
)。
窗口间通信与 opener
属性
新创建窗口的 window
对象包含 opener
属性 ,指向打开它的窗口(仅在弹出窗口的最上层 window
对象 top
中定义):
JavaScript
let wileyWin = window.open("http://www.wiley.com/", "wileyWindow", "...");
alert(wileyWin.opener === window); // true(指向调用 open() 的窗口)
限制:
- 窗口不会自动跟踪自己打开的新窗口,需开发者手动记录引用。
- 部分浏览器中,标签页运行在独立进程,若需跨标签通信,需避免进程隔离。可将新窗口的
opener
设为null
,表示无需通信,允许其在独立进程运行:
JavaScript
let wileyWin = window.open("http://www.wiley.com/", "wileyWindow", "...");
wileyWin.opener = null; // 解除与父窗口关联,允许独立进程运行
2. 安全限制
弹出窗口曾因在线广告滥用(伪装成系统对话框,用户难以区分来源),浏览器对其施加限制:
- 仅允许用户操作后创建弹窗 (如点击鼠标、按下键盘),网页加载过程中调用
window.open()
无效,可能显示错误。
3. 弹窗屏蔽程序
所有现代浏览器内置弹窗屏蔽程序,大多数意外弹窗会被屏蔽。若弹窗被阻止:
- 浏览器内置屏蔽 :
window.open()
返回null
,可通过检测返回值判断:
JavaScript
let wileyWin = window.open("http://www.wiley.com", "_blank");
if (wileyWin === null) {
alert("The popup was blocked!"); // 弹窗被屏蔽
}
- 扩展/程序屏蔽 :
window.open()
可能抛出错误,需结合try/catch
检测:
JavaScript
let blocked = false;
try {
let wileyWin = window.open("http://www.wiley.com", "_blank");
if (wileyWin === null) blocked = true;
} catch (ex) {
blocked = true; // 捕获屏蔽错误
}
if (blocked) {
alert("The popup was blocked!");
}
注意:检测弹窗是否被屏蔽不影响浏览器显示弹窗被屏蔽的系统消息。
9. 定时器
JavaScript 在浏览器中是单线程执行,但允许通过定时器指定在未来时间或间隔执行代码:
setTimeout()
:指定一段时间后执行代码(一次性)。setInterval()
:指定每隔一段时间执行代码(周期性)。
setTimeout()
语法 :接收两个参数,要执行的代码 (函数或字符串,类似 eval()
)和等待时间(毫秒) 。示例:
JavaScript
// 在1秒后显示警告框
setTimeout(() => alert("Hello world!"), 1000); // 使用箭头函数
setTimeout()
的第二个参数是等待时间(毫秒) ,而非执行代码的精确时间。JavaScript 是单线程的 ,通过任务队列调度代码执行:setTimeout()
会在指定时间后将任务加入队列,若队列空闲则立即执行,否则需等待前面任务完成。
超时任务的取消
setTimeout()
返回超时 ID (数值标识符),可用于通过 clearTimeout()
取消未执行的任务:
JavaScript
// 设置超时任务(1秒后执行)
let timeoutId = setTimeout(() => alert("Hello world!"), 1000);
// 取消超时任务(必须在执行前调用)
clearTimeout(timeoutId);
注意 :任务执行后调用 clearTimeout()
无效。
超时任务的作用域与 this
指向
-
所有超时执行的函数在全局作用域的匿名函数中运行:
- 非严格模式:
this
指向window
; - 严格模式:
this
为undefined
; - 箭头函数:
this
继承定义时的词法作用域。
- 非严格模式:
setInterval()
周期性执行
setInterval()
与 setTimeout()
用法类似,但任务会每隔指定时间执行一次 ,直到取消或页面卸载。参数:执行代码(函数/字符串)、添加下一次任务到队列的间隔时间(毫秒)。示例:
JavaScript
// 每10秒执行一次 alert
setInterval(() => alert("Hello world!"), 10000);
关键特性:
- 间隔时间指上一次任务加入队列后,到下一次任务加入队列的等待时间,与任务实际执行时长无关。
- 若任务执行时间超过间隔时间,会导致任务叠加(浏览器不关心执行耗时,到点即添加新任务)。因此,执行时间短、非阻塞的回调更适合
setInterval()
。
周期性任务的取消
setInterval()
返回循环定时 ID ,通过 clearInterval()
取消:
JavaScript
let num = 0, intervalId = null;
const max = 10;
const incrementNumber = function() {
num++;
// 达到最大值时取消循环
if (num === max) {
clearInterval(intervalId); // 传入定时 ID 取消
}
};
// 启动循环任务(每秒执行一次)
intervalId = setInterval(incrementNumber, 1000);
注意 :若不主动取消,setInterval()
会持续执行直到页面卸载。
JavaScript
alert("Done");
}
// 设置循环定时任务(每500ms执行一次 incrementNumber)
intervalId = setInterval(incrementNumber, 500);
在这个例子中,变量 num
会每半秒递增一次,直至达到最大值,此时循环定时会被取消。这种周期性任务也可以通过 setTimeout()
嵌套调用来实现,示例如下:
JavaScript
let num = 0;
let max = 10;
let incrementNumber = function() {
num++;
// 如果还没有达到最大值,再设置一个超时任务(递归调用)
if (num < max) {
setTimeout(incrementNumber, 500); // 500ms后再次执行自身
} else {
alert("Done"); // 达到最大值时停止
}
};
// 启动首次超时任务
setTimeout(incrementNumber, 500);
setTimeout()
嵌套 vs setInterval()
推荐使用 setTimeout()
嵌套实现循环任务,原因如下:
- 无需记录超时 ID:满足条件时自动停止,否则自动设置下一个超时任务。
- 避免任务叠加/跳过 :
setInterval()
无法保证前一个任务结束后才开始下一个(若任务执行时间超过间隔,可能导致任务堆积或跳过);setTimeout()
嵌套会在前一个任务完成后才安排下一个,确保间隔准确。 - 生产环境更可靠 :
setInterval()
在实践中很少用于生产环境,setTimeout()
嵌套是更安全的做法。
10. 系统对话框
通过 alert()
、confirm()
和 prompt()
方法可调用系统对话框,用于向用户显示消息。
特性:
- 与网页无关:外观由操作系统/浏览器决定,无法用 CSS 美化,不包含 HTML。
- 同步模态:显示时代码暂停执行,关闭后恢复。
警告框(alert()
)
- 功能:显示消息,用户只能点击"OK"关闭。
- 参数 :仅接收一个字符串参数 (非字符串会自动调用
toString()
转换)。 - 用途:展示不可控消息(如报错),示例:
JavaScript
alert("Hello World"); // 显示包含"Hello World"的对话框
alert(123); // 自动转换为字符串:"123"
注意 :与
console.log()
不同,alert()
不支持多参数,仅显示首个参数的字符串形式。
确认框(confirm()
)
confirm()
显示带"OK"和"Cancel"按钮的对话框,用于让用户确认操作。
-
返回值:
true
:用户点击"OK"按钮;false
:用户点击"Cancel"按钮或关闭对话框(如点击右上角×)。
-
示例:
JavaScript
if (confirm("Are you sure?")) {
alert("I'm so glad you're sure!"); // OK按钮
} else {
alert("I'm sorry to hear you're not sure."); // Cancel或关闭
}
- 用途 :适用于需要用户确认的关键操作(如删除数据),会阻断页面交互,建议必要时使用。
提示框(prompt()
)
prompt()
显示带文本输入框的对话框,用于获取用户输入,包含"OK""Cancel"按钮。
-
参数:
- 第一个参数:显示给用户的提示文本;
- 第二个参数:输入框的默认值(可选,可为空字符串)。
-
返回值:
- 用户点击"OK":返回输入框中的值(字符串);
- 用户点击"Cancel"或关闭对话框:返回
null
。
-
示例:
JavaScript
let result = prompt("What is your name?", ""); // 第二个参数为空默认值
if (result !== null) {
alert("Welcome, " + result); // 显示用户输入
}
系统对话框特点总结
-
无需HTML/CSS:由系统/浏览器渲染,样式不可定制。
-
同步阻塞:显示时暂停代码执行,关闭后恢复。
-
用途明确:
alert()
:展示不可交互的消息;confirm()
:获取用户的"确认/取消"选择;prompt()
:收集简单文本输入。
系统对话框是 Web 应用程序简单快捷的沟通手段。浏览器对系统对话框有特殊限制:若脚本生成多个对话框,除第一个外,后续对话框会显示复选框,用户勾选后可禁用后续弹窗,直至页面刷新。
- 禁用后:页面刷新前所有系统对话框(警告框、确认框、提示框)均被屏蔽,且开发者无法获知对话框是否显示。
- 独立性 :两次独立用户操作产生的对话框(如两次点击触发的
alert
)均不显示复选框;连续操作产生的多个对话框,从第二个开始显示复选框。
其他系统对话框(异步)
JavaScript 还支持两种异步系统对话框 ,通过 window
对象调用,不阻塞脚本执行:
-
打印对话框(
print()
)- 功能:显示浏览器打印界面,与用户从菜单选择"打印"效果一致。
- 调用:
window.print();
-
查找对话框(
find()
)- 功能:显示浏览器查找界面,允许用户在页面中搜索文本。
- 调用:
window.find();
特点:
- 无返回值:无法获取用户操作结果(如是否打印、查找内容)。
- 不影响对话框计数器:不会被用户禁用弹窗的设置影响,也不计入浏览器的弹窗限制。
11. location
对象
location
是 BOM 中最有用的对象之一,提供当前窗口加载文档的信息及导航功能。
- 双重属性 :既是
window
的属性(window.location
),也是document
的属性(document.location
),指向同一个对象。 - 核心功能:解析当前 URL 为离散片段,可通过属性访问(见下表)。
location
对象 URL 解析属性
假设当前 URL 为:http://user:password@www.wiley.com:80/WileyCDA/?q=javascript#contents
属性 | 值 | 说明 |
---|---|---|
location.hash |
"#contents" |
URL 散列值(# 后内容,无则为空字符串) |
location.host |
"www.wiley.com:80" |
服务器名+端口号 |
location.hostname |
"www.wiley.com" |
服务器名(不含端口) |
location.href |
"http://www.wiley.com:80/WileyCDA/?q=javascript#contents" |
完整 URL(location.toString() 返回值) |
location.pathname |
"/WileyCDA/" |
URL 路径和文件名 |
location.port |
"80" |
端口号(URL 中无端口时返回空字符串) |
location.protocol |
"http:" |
协议(通常为 http: 或 https: ) |
location.search |
"#q=javascript" |
URL 查询字符串(? 后内容) |
location.username |
"user" |
域名前指定的用户名(如 user@domain.com 中的 user ) |
location.password |
"password" |
域名前指定的密码(如 user:password@domain.com 中的 password ) |
location.origin |
"http://www.wiley.com" |
URL 源地址(协议+域名+端口,只读) |
注意 :处理
location
对象时,URL
API 和URLSearchParams
API 非常有用(详情请参阅第 18 章)。
操作地址
通过修改 location
对象可修改浏览器地址,实现导航功能:
1. 直接导航(assign()
方法)
- 作用:立即导航到指定 URL,浏览器历史记录增加一条记录。
- 调用方式:
JavaScript
location.assign("http://www.wiley.com"); // 显式调用 assign()
2. 简化导航(修改 href
或 window.location
)
- 等价操作 :设置
location.href
或window.location
与调用assign()
效果相同,最常用:
JavaScript
window.location = "http://www.wiley.com"; // 直接赋值 location
location.href = "http://www.wiley.com"; // 修改 href 属性(推荐)
3. 修改 URL 片段(部分属性)
修改 hash
、search
、hostname
、pathname
、port
等属性会更新当前 URL ,示例如下(假设当前 URL 为 http://www.wiley.com/WileyCDA/
):
操作 | 结果 URL | 说明 |
---|---|---|
location.hash = "#section1" |
http://www.wiley.com/WileyCDA/#section1 |
修改哈希值(# 后内容) |
location.search = "?q=javascript" |
http://www.wiley.com/WileyCDA/?q=javascript |
修改查询字符串(? 后内容) |
location.hostname = "www.example.com" |
http://www.example.com/WileyCDA/ |
修改域名 |
location.pathname = "/mydir" |
http://www.wiley.com/mydir/ |
修改路径 |
location.port = "8080" |
http://www.wiley.com:8080/WileyCDA/ |
修改端口号 |
关键特性:
- 修改
hash
会在浏览器历史中增加一条记录,但不会重新加载页面; - 修改其他属性(如
search
、hostname
等)会导致页面重新加载新 URL。
修改地址的特殊方法
1. 替换历史记录(replace()
)
location.replace(URL)
导航到指定 URL,但不会在浏览器历史中增加新记录(替换当前历史记录)。用户点击"后退"按钮无法返回上一页。
- 示例:
HTML
<!DOCTYPE html>
<html>
<head>
<title>You won't be able to get back here</title>
</head>
<body>
<p>Enjoy this page for a second, because you won't be coming back here.</p>
<script>
// 1秒后重定向,替换当前历史记录
setTimeout(() => location.replace("http://www.wiley.com/"), 1000);
</script>
</body>
</html>
效果 :页面加载1秒后重定向到 www.wiley.com
,浏览器"后退"按钮禁用,无法返回原页面。
2. 重新加载页面(reload()
)
location.reload()
重新加载当前页面,参数控制加载方式:
- 无参数:浏览器可能从缓存加载(最快方式);
true
参数:强制从服务器重新加载(忽略缓存)。- 示例:
JavaScript
location.reload(); // 重新加载,可能使用缓存
location.reload(true); // 强制从服务器加载
注意 :reload()
之后的代码可能因网络延迟或资源加载被中断,建议作为最后一行代码执行。
12. navigator
对象
navigator
对象由 Netscape Navigator 2 引入,用于客户端浏览器标识,所有启用 JavaScript 的浏览器均支持,但属性因浏览器而异。
常用属性/方法(部分)
属性/方法 | 说明 |
---|---|
appCodeName |
浏览器代码名(非 Mozilla 浏览器也可能返回 "Mozilla" ) |
appName |
浏览器全名 |
appVersion |
浏览器版本(通常与实际版本不一致) |
cookieEnabled |
布尔值,指示是否启用 Cookie |
battery |
返回 BatteryManager 对象(电池状态 API) |
connection |
返回 NetworkInformation 对象(网络信息 API) |
activeVRDisplays |
返回数组,包含 isPresenting 为 true 的 VR 显示设备实例 |
credentials |
返回 CredentialsContainer 对象(凭证管理 API) |
deviceMemory |
返回设备内存容量(单位:GB) |
doNotTrack |
返回用户"不跟踪"(do-not-track)设置 |
geolocation |
返回 Geolocation 对象(地理定位 API) |
getVRDisplays() |
返回数组,包含可用的 VR 显示设备实例 |
getUserMedia() |
返回与媒体设备关联的流(如摄像头/麦克风,WebRTC API) |
hardwareConcurrency |
返回设备 CPU 核心数量 |
javaEnabled() |
布尔值,指示是否启用 Java |
language |
浏览器主语言(如 "zh-CN" ) |
languages |
浏览器偏好语言数组(如 ["zh-CN", "en-US"] ) |
locks |
返回 LockManager 对象(Web Locks API,用于资源锁定) |
maxTouchPoints |
设备触摸屏支持的最大触摸点数 |
mimeTypes |
浏览器注册的 MIME 类型数组 |
online |
布尔值,指示浏览器是否联网 |
oscpu |
浏览器运行设备的操作系统和 CPU 信息 |
permissions |
返回 Permissions 对象(权限 API,管理设备权限) |
platform |
浏览器运行的系统平台(如 "Win32" 、"MacIntel" ) |
plugins |
浏览器安装的插件数组 |
userAgent |
浏览器用户代理字符串(用于标识浏览器类型/版本/系统) |
vibrate() |
触发设备振动(如手机振动,参数为振动时长毫秒) |
webdriver |
布尔值,指示浏览器是否被自动化程序(如 Selenium)控制 |
注意 :
navigator
属性因浏览器实现差异较大,生产环境中建议结合特性检测(而非依赖具体值)。
核心用途
navigator
对象的属性常用于浏览器/设备检测 (如通过 userAgent
判断浏览器类型、hardwareConcurrency
获取 CPU 核心数等),但需注意不同浏览器实现差异,建议优先使用特性检测(如检查 API 是否存在)而非依赖具体属性值。
注册协议处理程序(registerProtocolHandler()
)
navigator.registerProtocolHandler()
可将网站注册为特定协议的默认处理程序 (如邮件、FTP),使 Web 应用程序像桌面软件一样响应协议请求(如 mailto:
链接)。
-
参数(必须传入3个):
- 协议 :要处理的协议(如
"mailto"
、"ftp"
); - 处理 URL :接收请求的 Web 应用 URL,
%s
表示原始请求内容; - 应用名称:显示给用户的处理程序名称。
- 协议 :要处理的协议(如
-
示例 :注册 Web 邮件客户端处理
mailto:
协议
perl
JavaScript
navigator.registerProtocolHandler(
"mailto", // 处理的协议
"http://www.example.com?cmd=%s", // 处理请求的 URL(%s 替换为原始邮件地址)
"Some Mail Client" // 应用名称
);
效果 :点击 mailto:user@example.com
链接时,会调用 http://www.example.com?cmd=user@example.com
处理请求。
13. screen
对象
screen
是 window
的属性,提供客户端显示器信息(如分辨率、可用区域),编程中较少使用。属性均为只读,不同浏览器实现略有差异。
screen
对象属性
属性 | 说明 |
---|---|
availHeight |
屏幕高度(像素)减去系统组件高度(如任务栏) |
availWidth |
屏幕宽度(像素)减去系统组件宽度 |
availLeft |
屏幕左侧未被系统组件占用的像素位置 |
availTop |
屏幕顶部未被系统组件占用的像素位置 |
height |
屏幕总高度(像素,含系统组件) |
width |
屏幕总宽度(像素,含系统组件) |
colorDepth |
屏幕颜色位数(通常为32位,即真彩色) |
pixelDepth |
屏幕位深(与 colorDepth 通常一致) |
orientation |
返回 ScreenOrientation 对象(屏幕朝向 API) |
14. history
对象
history
是 window
的属性,记录当前窗口的用户导航历史。
-
核心特性:
- 每个窗口/标签页有独立的
history
对象; - 安全限制:不暴露具体 URL,仅允许通过 API 前进/后退。
- 每个窗口/标签页有独立的
-
主要用途:在不获取实际 URL 的情况下,控制页面导航(如前进、后退、修改历史记录)。
注:详细 API(如
pushState()
、replaceState()
)将在后续章节介绍,基础导航可通过history.back()
、history.forward()
、history.go(n)
实现。
go()
方法
history.go()
用于在用户历史记录中导航,支持前进或后退指定步数,参数为整数:
- 负值 :后退(如
-1
对应浏览器"后退"按钮); - 正值 :前进(如
1
对应浏览器"前进"按钮)。
示例:
JavaScript
history.go(-1); // 后退一页(等价于 history.back())
history.go(1); // 前进一页(等价于 history.forward())
history.go(2); // 前进两页
旧版浏览器特性 :参数曾支持字符串,此时会导航到历史记录中包含该字符串的首个页面(无匹配则不执行),如
history.go("wiley.com")
(现代浏览器不推荐使用)。
简写方法:back()
和 forward()
history.back()
:后退一页(等价于history.go(-1)
);history.forward()
:前进一页(等价于history.go(1)
)。
示例:
JavaScript
history.back(); // 后退一页
history.forward(); // 前进一页
length
属性
history.length
返回历史记录中的条目数(包含可前进和后退的页面),初始页面(窗口/标签页首次加载)的 length
为 1
。
用途:判断用户是否从当前页面开始导航,示例:
JavaScript
if (history.length === 1) {
// 当前是窗口中的第一个页面(用户直接打开,未通过历史记录导航而来)
}
注意事项
URL 变化会生成历史记录条目:
- 包括修改 URL 散列值(
location.hash
),会新增历史记录(常用于单页应用模拟导航,避免页面刷新)。 - 此特性被单页应用框架广泛用于实现前进/后退功能,无需重新加载页面。
15. 历史状态管理
现代 Web 应用需解决"无刷新导航"问题,HTML5 引入 历史状态管理 API ,允许修改浏览器 URL 而不加载新页面,核心方法为 history.pushState()
和 history.replaceState()
。
1. pushState()
:添加历史记录
history.pushState(state, title, url)
可在不刷新页面的情况下,向历史记录添加新状态并修改 URL。
-
参数:
state
:状态对象(随历史记录保存,可通过popstate
事件访问),大小限制通常为 500KB~1MB,需包含页面状态初始化信息(仅支持可序列化数据,如对象、数组,不支持 DOM 元素)。title
:新状态标题(当前浏览器多未使用,可传空字符串或短标题)。url
(可选):新 URL(相对路径或绝对路径,需同域,否则报错)。
-
示例:
JavaScript
let stateObject = { foo: "bar" }; // 状态对象(需可序列化)
history.pushState(stateObject, "My title", "baz.html"); // 添加新状态
-
执行效果:
- 浏览器地址栏显示
baz.html
(URL 更新); - 历史记录新增一条条目,"后退"按钮启用;
- 不发送服务器请求 ,
location.href
返回新 URL。
- 浏览器地址栏显示
2. popstate
事件:监听历史导航
当用户点击"后退"/"前进"按钮时,会触发 window
对象的 popstate
事件 ,事件对象的 state
属性包含 pushState()
保存的状态对象。
-
注意:
- 初始页面加载时(无历史记录),
event.state
为null
; - 仅通过历史记录导航(如
back()
、forward()
、go()
)时触发,直接调用pushState()
不会触发。
- 初始页面加载时(无历史记录),
-
示例:
JavaScript
window.addEventListener("popstate", (event) => {
let state = event.state; // 获取状态对象
if (state) { // 初始页面 state 为 null
processState(state); // 根据状态重置页面
}
});
3. replaceState()
:替换当前历史记录
history.replaceState(state, title, url)
与 pushState()
参数相同,但 不创建新历史记录,仅替换当前状态(不启用"后退"按钮)。
- 示例:
JavaScript
history.replaceState({ newFoo: "newBar" }, "New title"); // 替换当前状态
核心注意事项
- 状态对象限制:仅包含可序列化数据(避免 DOM 元素),大小通常限制在 500KB~1MB。
- URL 合法性 :
pushState()
创建的"假 URL"需对应服务器真实资源,否则刷新页面会导致 404 错误(单页应用需通过服务器配置解决,如 Nginx 重定向)。 - 兼容性:所有现代浏览器支持,无需考虑旧版 IE。
总结
pushState()
:新增历史记录,修改 URL,支持"后退"导航。replaceState()
:替换当前历史记录,不新增条目。popstate
事件:监听历史导航,恢复对应状态。- 核心价值:实现单页应用(SPA)无刷新导航,提升用户体验。
16. 小结
浏览器对象模型(BOM,Browser Object Model) 以 window
对象为基础,代表浏览器窗口和页面可见区域。window
同时作为 ECMAScript 的 Global
对象,所有全局变量、函数及原生类型构造函数均为其属性。本章核心内容如下:
1. 窗口操作
- 引用其他窗口 :通过窗口指针(如
iframe
名称、window.open()
返回值)操作其他window
对象。
2. 导航控制(location
对象)
- 操纵 URL :通过修改
location
属性(如href
、hash
、search
)改变浏览器 URL 的部分或全部,实现导航。 - 替换历史记录 :
location.replace(URL)
可导航到新 URL 并替换当前历史记录(用户无法通过"后退"返回原页面)。
3. 浏览器信息(navigator
对象)
- 提供浏览器相关信息 :属性因浏览器而异,但
userAgent
(用户代理字符串)为所有浏览器支持,常用于浏览器检测。
4. 其他 BOM 对象
-
screen
对象:存储客户端显示器信息(如分辨率、可用区域),用于评估设备能力。 -
history
对象:操纵浏览器历史记录,支持:- 导航(
back()
、forward()
、go()
); - 修改历史记录(
pushState()
、replaceState()
,实现无刷新 URL 变更)。
- 导航(
BOM 提供了与浏览器交互的核心能力,通过这些对象可实现窗口控制、导航管理、设备信息获取及历史记录操作。