# window对象
window 对象在浏览器中有两重身份,一个是ECMAScript 中的 Global 对象,另一个就是浏览器窗口的 JavaScript 接口。
# Global 作用域
通过 var 声明的所有全局变量和函数都会变成 window 对象的属性和方法。使用 let 或 const 替代 var,则不会把变量添加给全局对象。可以在 window 对象上查询是否存在可能未声明的变量
// 这会导致抛出错误,因为 oldValue 没有声明
var newValue = oldValue;
// 这不会抛出错误,因为这里是属性查询
// newValue 会被设置为 undefined
var newValue = window.oldValue;
# 窗口关系
top 对象始终指向最上层(最外层)窗口,即浏览器窗口本身。而 parent 对象则始终指向当前窗 口的父窗口。如果当前窗口是最上层窗口,则 parent 等于 top(都等于 window)。最上层的 window 如果不是通过 window.open()打开的,那么其 name 属性就不会包含值。
self 对象,它是终极 window 属性,始终会指向 window。实际上,self 和 window 就 是同一个对象。
self === window // true
# 窗口位置与像素比
现代浏览器提供了 screenLeft 和screenTop 属性,用于表示窗口相对于屏幕左侧和顶部的位置 ,返回值的单位是 CSS 像素。
window.devicePixelRatio 表示物理像素与逻辑像素之间的缩放系数。
# 窗口大小
outerWidth 和 outerHeight 返回浏览器窗口自身的大小(不管是在最外层 window 上使用,还是在窗格中使用)。
innerWidth和 innerHeight 返回浏览器窗口中页面视口的大小(不包含浏览器边框和工具栏)。
document.documentElement.clientWidth 和 document.documentElement.clientHeight 返回页面视口的宽度和高度。
确定页面视口的大小:
const pageWidth = window.innerWidth,
pageHeight = window.innerHeight;
if (typeof pageWidth != "number") {
if (document.compatMode == "CSS1Compat"){
pageWidth = document.documentElement.clientWidth;
pageHeight = document.documentElement.clientHeight;
} else {
pageWidth = document.body.clientWidth;
pageHeight = document.body.clientHeight;
}
}
// 可以简写为
const pageWidth = window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth,
pageHeight = window.innerHeight || document.documentElement.clientHeight || document.body.clientHeight;
# 视口位置
度量文档相对于视口滚动距离的属性有两对,返回相等的值:window.pageXoffset/window. scrollX 和 window.pageYoffset/window.scrollY。
scroll()、scrollTo()和 scrollBy()方法滚动页面,都接收表示相对视口距离的 x 和 y 坐标,这两个参数在前两个方法中表示要滚动到的坐标,在最后一个方法中表示滚动的距离,也都接收一个 ScrollToOptions 字典,除了提供偏移值,还可以通过 behavior 属性告诉浏览器是否平滑滚动
// 滚动到距离屏幕左边及顶边各 100 像素的位置, 重复多次执行滚动条距离不变
window.scroll(100, 100);
window.scrollTo(100, 100);
// 相对于当前视口向下滚动 100 像素,重复多次执行,每执行一次,滚动条向下滚动100像素
window.scrollBy(0, 100);
// 平滑滚动
window.scrollTo({
left: 100,
top: 100,
behavior: 'smooth'
});
# 导航与打开新窗口
window.open()方法可以用于导航到指定 URL,也可以用于打开新浏览器窗口。这个方法接收 4个参数:要加载的 URL、目标窗口、特性字符串和表示新窗口在浏览器历史记录中是否替代当前加载页面的布尔值。通常,调用这个方法时只传前 3 个参数,最后一个参数只有在不打开新窗口时才会使用。
如果 window.open()的第二个参数是一个已经存在的窗口或窗格(frame)的名字,则会在对应的 窗口或窗格中打开 URL。
判断调用 window.open()的弹窗是否被屏蔽了:
let blocked = false;
try {
let wroxWin = window.open("http://www.wrox.com", "_blank");
if (wroxWin == null){
blocked = true;
}
} catch (ex){
blocked = true;
}
if (blocked){
alert("The popup was blocked!");
}
# 定时器
JavaScript 是单线程的,所以每次只能执行一段代码。为了调度不同代码的执行,JavaScript 维护了一个任务队列。其中的任务会按照添加到队列的先后顺序执行。setTimeout()的第二个参数只是告诉 JavaScript 引擎在指定的毫秒数过后把任务添加到这个队列。如果队列是空的,则会立即执行该代码。如果队列不是空的,则代码必须等待前面的任务执行完才能执行。
setInterval()第二个参数,也就是间隔时间,指的是向队列添加新任务之前等待的时间。比如,调用 setInterval()的时间为 01:00:00,间隔时间为 3000 毫秒。这意味着 01:00:03 时,浏览器会把任务添加到执行队列。浏览器不关心这个任务什么时候执行或者执行要花多长时间。因此,到了01:00:06,它会再向队列中添加一个任务。由此可看出,执行时间短、非阻塞的回调函数比较适合 setInterval()。
所有超时执行的代码(函数)都会在全局作用域中的一个匿名函数中运行,因此函数中的 this 值在非严格模式下始终指向 window,而在严格模式下是 undefined。如果给 setTimeout()提供了一个箭头函数,那么 this 会保留为定义它时所在的词汇作用域。
# 系统对话框
- 警告框
通过调用alert()方法来显示,它接收一个要显示给用户的字符串。
alert('Are you sure?!')
- 确认框
通过调用 confirm()来显示,confirm()方法的返回值:true 表示单击了 OK 按钮,false 表示单击了 Cancel 按钮或者通过单击某一角上的 X 图标关闭了确认框。
if (confirm("Are you sure?")) {
alert("I'm so glad you're sure!");
} else {
alert("I'm sorry to hear you're not sure.");
}
- 提示框
通过调用 prompt()方法来显示,prompt()方法接收两个参数:要显示给用户的文本,以及文本框的默认值(可以是空字符串)。可以这样设置默认值prompt("What is your name?","Jake")。如果用户单击了 OK 按钮,则 prompt()会返回文本框中的值。如果用户单击了 Cancel 按钮,或者对话框被关闭,则 prompt()会返回 null。
let result = prompt("What is your name? ", "");
if (result !== null) {
alert("Welcome, " + result);
}
# location对象
# 查询字符串
# 操作地址
# navigator对象
# 检测插件
# 注册处理程序
# screen对象
这个对象不经常使用,这里简单罗列了几个可能会用到的属性
| 属性 | 说明 |
|---|---|
| availHeight | 屏幕像素高度减去系统组件高度(只读) |
| availLeft | 没有被系统组件占用的屏幕的最左侧像素(只读) |
| availTop | 没有被系统组件占用的屏幕的最顶端像素(只读) |
| availWidth | 屏幕像素宽度减去系统组件宽度(只读) |
| colorDepth | 表示屏幕颜色的位数;多数系统是 32(只读) |
| height | 屏幕像素高度 |
| left | 当前屏幕左边的像素距离 |
| pixelDepth | 屏幕的位深(只读) |
| top | 当前屏幕顶端的像素距离 |
| width | 屏幕像素宽度 |
| orientation | 返回 Screen Orientation API 中屏幕的朝向 |
# history对象
history 对象提供了操纵浏览器历史记录的能力,开发者可以确定历史记录中包含多少个条目,并以编程方式实现在历史记录中导航,而且也可以修改历史记录。
# 导航
go()方法可以在用户历史记录中沿任何方向导航,可以前进也可以后退。这个方法只接收一个参数,这个参数可以是一个整数,表示前进或后退多少步。负值表示在历史记录中后退(类似点击浏览器的“后退”按钮),而正值表示在历史记录中前进(类似点击浏览器的“前进”按钮)。
go()有两个简写方法:back()和 forward()。
// 后退一页
history.back();
// 前进一页
history.forward();
history 对象还有一个 length 属性,表示历史记录中有多个条目
如果页面 URL 发生变化,则会在历史记录中生成一个新条目。对于 2009 年以来发布的主流浏览器,这包括改变 URL 的散列值(因此,把 location.hash 设置为一个新值会在这些浏览器的历史记录中增加一条记录)。这个行为常被单页应用程序框架用来模拟前进和后退,这样做是为了不会因导航而触发页面刷新。
# 历史状态管理
hashchange 会在页面 URL 的散列变化时被触发,开发者可以在此时执行某些操作。而状态管理API 则可以让开发者改变浏览器 URL 而不会加载新页面
history.pushState()这个方法接收 3 个参数:一个 state 对象、一个新状态的标题和一个(可选的)相对 URL。pushState()方法执行后,状态信息就会被推到历史记录中,浏览器地址栏也会改变以反映新的相对 URL。除了这些变化之外,即使 location.href 返回的是地址栏中的内容,浏览器页不会向服务器发送请求。第二个参数并未被当前实现所使用,因此既可以传一个空字符串也可以传一个短标题。第一个参数应该包含正确初始化页面状态所必需的信息。为防止滥用,这个状态的对象大小是有限制的,通常在 500KB~1MB 以内。
let stateObject = {foo:"bar"};
history.pushState(stateObject, "My title", "baz.html");
pushState()会创建新的历史记录,所以也会相应地启用“后退”按钮。此时单击“后退”按钮,就会触发 window 对象上的 popstate 事件。popstate 事件的事件对象有一个 state 属性,其中包含通过 pushState()第一个参数传入的 state 对象:
window.addEventListener("popstate", (event) => {
let state = event.state;
if (state) { // 第一个页面加载时状态是 null
processState(state);
}
});
history.state 获取当前的状态对象
replaceState()传入两个参数来更新状态
history.replaceState({newFoo: "newBar"}, "New title");
传给 pushState()和 replaceState()的 state 对象应该只包含可以被序列化的信息。因此,DOM 元素之类并不适合放到状态对象里保存。
注意
使用 HTML5 状态管理时,要确保通过 pushState()创建的每个“假”URL 背后都对应着服务器上一个真实的物理 URL。否则,单击“刷新”按钮会导致 404 错误。所有单页应用程序(SPA,Single Page Application)框架都必须通过服务器或客户端的某些配置解决这个问题。
← 第十一章、期约与异步函数 第十四章、DOM →