1.什么是 BOM
BOM(Browser Object Model)即浏览器对象模型。
关于 BOM 的说明:
- BOM 提供了独立于內容,而与浏览器窗口进行交互的对象。
- 由于 BOM 主要用于管理窗口和窗口之间的通讯,因此其核心对象是
window
对象。 - BOM 由一系列相关的对象构成,并且每个对象都提供了很多方法与属性。
- BOM 缺乏一个统一的标准:
- JavaScript 语法的标准组织是 ECMA
- DOM 的标准组织是 W3C(所有浏览器公共遵守的标准)。
- BOM 是各个浏览器厂商根据 DOM 在各自浏览器上的表现(表现为不同浏览器定义有差别,实现方式不同)。
注意:通常情况下如果提到 BOM,一般指的都是 window
对象。
2.BOM 和 DOM 之间的关系
可以认为 BOM 是浏览器窗口,DOM 则是浏览器窗口中的页面。
总结:
- DOM 通过
document
对象来访问、控制、修改 html 和 xhtml 等文档中的内容。 - BOM 通过
window
对象来访问、控制、修改浏览器中的內容。 - 联系:
- BOM 包含 DOM,浏览器提供用来访问的是 BOM 对象,从 BOM 对象可以访问到 DOM 对象,从而使 JavaScript 可以操作浏览器,并通过操作浏览器读取到文档的內容。
- 区别:
- DOM 描述了处理网页內容的方法和接口,即操作页面内部。BOM 描述了与浏览器进行交互的方法和接口,即操作页面之间。
3.window 对象
window 对象是 BOM 的具体表现形式。window 和 BOM 之间的关系就像 document 和 DOM 之间的关系一样,BOM 相当于 DOM,window 相当于 document。
注意:因为 window
对象是 JS 中的顶级对象,因此所有定义在全局作用域中的变量、函数都会变成 window
对象的属性和方法,在调用的时候可以省略 window
。
例如:
// 打开窗口
window.open(url); // 等价于 open(url);
// 关闭窗口
window.close(); // 等价于 close();
// 获取事件
window.event; // 等价于 event
// 获取文档
window.document; // 等价于 document
3.1 window 对象中常用的属性和方法
3.1.1 window.name
属性:
window.name
是 window
对象的一个属性,默认值为空。
特性:
window.name
值在不同的页面(甚至不同域名)加载后依旧存在,并且可以支持非常长的 name
值(2MB左右)。
应用:
正是由于 window.name
属性拥有在不同页面依旧存在的特性,因此出现了一门叫做 跨域传输 的技巧。而这个技巧的内部实现原理就是 window.name
的持久性的特征。
3.1.2 window 尺寸属性
-
window.outerHeight
和window.outerWidth
,这两个属性返回的是整个浏览器的高度,和页面窗口的大小没有任何关系console.log("outerHeight " + window.outerHeight); console.log("outerWidth " + window.outerWidth);
-
window.innerHeight
和window.innerWidth
,返回视口的高度和宽度(计算滚动条),页面变化它就变。console.log("innerHeight " + window.innerHeight); console.log("innerWidth " + window.innerWidth);
-
document.documentElement.clientHeight
和document.documentElement.clientWidth
,返回视口的高度和宽度(不计算滚动条)。console.log("clientHeight " + document.documentElement.clientHeight); console.log("clientWidth " + document.documentElement.clientWidth);
-
window.pageXOffset
和window.pageYOffset
返回页面滚动的距离(通用),这两个属性指的是页面发生滚动的距离。console.log("pageYOffset: " + window.pageYOffset); console.log("pageXOffset: " + window.pageXOffset);
-
window.screenY
和window.screenX
返回浏览器距离屏幕左上角的距离。console.log("screenY: " + window.screenY); console.log("screenX: " + window.screenX);
3.1.3 window.navigator 对象属性
window.navigator
对象包含大量有关 Web 浏览器的信息,在检测浏览器及操作系统上非常有用。(这个对象和 event
一样,是全局并且唯一的。)
navigator.appCodeName // 浏览器代码名的字符串表示
navigator.appName // 官方浏览器名的字符串表示
navigator.appVersion // 浏览器版本信息的字符串表示
navigator.cookieEnable // 如果启用 cookie 返回 true,否则返回 false
navigator.javaEnable // 如果启用 java 则返回 true,否则返回 false
navigator.platform // 浏览器所在计算机平台的字符串表示
navigator.plugins // 安装在浏览器中的插件数组
navigator.userAgent // 返回和浏览器内核相关的信息(加粗)
注意:如果 window.navigator.userAgent
出现了 Mobile,则可以确定用户使用的是移动设备。
3.2 window 对象中涉及的其它方法
3.2.1 alert
alert
是一个警示框,作用是提示用户信息,该方法执行后无返回值。
语法:
window.alert("Hello World!");
// 或
alert("Hello World!");
注意:警示框弹出后将阻断程序执行,必须关闭警示框程序才会继续执行。
3.2.2 prompt
prompt
也表示警示框,作用是提示用户信息,该方法执行后根据情况不同返回值略有不同。
- 点击取消:返回
null
- 没有默认值:
如果用户没有输入內容,返回一个空字符串。
如果用户输入了內容,返回值为用户输入的內容。 - 有默认值
如果用户没有输入內容,返回默认值
如果用户输入了內容,返回值为用户输入的內容。
语法:
// 默认值不是必须的
var res = prompt(msg, defaultMsg);
3.2.3 confirm
confirm
表示警示框,作用是提示用户信息,点击确认返回 true
,点击取消返回 false
。
语法:
var msg = window.confirm("我是 confirm");
console.log(msg);
注意:以上三种对话框都是模式对话框,即在用户点击确定按钮或者取消按钮把对话框关闭之前,它将阻止用户对浏览器的所有输入,并暂停对 JavaScript 代码的执行,在用户做出响应之前,不会执行下一条语句。
3.2.4 间隔调用和延迟调用
-
使用间隔调用
setInterval
方法用于实现间隔调用,又被称为定时器。是一种能够每隔一定时间自动执行一次的函数。
语法:var timer = null; timer = setInterval(function() { console.log("hello"); }, 1000);
以上代码会每隔 1s 打印一次 hello,所以
function
代表的是要被回调的函数,1000 代表的是函数调用的时间间隔。如果间隔调用的函数需要传入参数,则间隔调用需要使用如下的声明方式。
语法:var timer = null; timer = setInterval(字符串, 执行事件的时间间隔 ms);
例如:
var timer = null; function show(words) { console.log(words); } var timer = setInterval('show("hello")', 1000);
注意:
- 间隔调用不是立即执行,而是在 任务队列中的任务完成后 才执行间隔调用。
- 因为间隔调用函数的实际执行者是
window
,因此间隔调用内部的this
指向window
。
-
移除间隔调用
clearInterval
方法用于移除间隔调用
语法:clearInterval(timer);
上述代码能够将刚才创建的定时器移除掉。
注意:间隔调用的返回值是一个数字队列,因此通过访问数字队列来清除间隔调用也是被允许的。
例如:setInterval(function() { console.log("hello"); }, 1000); setTimeout(function() { clearInterval(1); }, 5000);
-
延迟调用
延迟调用又叫延迟调用函数。是一种能够等待一定事件后再去执行的函数。
语法:var timer = null; timer = setTimeout(需要执行的函数, 等待的时间);
例如:
var timer = setTimeout(function() { clearInterval(1); }, 5000);
上面代码的功能是在页面加载 5s 后清除定时器。
4.数据解析
数据解析是指将 不能被直接打开的数据 通过某种方法转变为 能够被直接使用的数据。
对于开发者来说最常见的数据解析就是将 字符串数据 解析为 对象数据。
例如:
function parseData() {
var obj = {};
var infoStr = document.location.search;
var realInfo = infoStr.slice(1);
var infoArr = realInfo.split("&");
for (var i = 0; i < infoArr.length; i++) {
var tempArr = infoArr[i].split("=");
obj[tempArr[0]] = decodeURIComponent(tempArr[1]);
}
return obj;
}
5.页面加载优化和 JS 文件解析顺序
在阅读下面的内容之前,先了解一下 JavaScript 引擎这个概念。
JS 引擎是由渲染引擎和解释器构成。
-
渲染引擎
- 解析代码:HTML 代码解析为 DOM 树
- 对象的合成:CSS 和 DOM 合成一棵渲染树
- 布局:计算出渲染树的布局
- 绘制:将渲染树绘制到屏幕
注意:这四步不一定严格按照顺序来执行。
JS 解释器
能够将 JS 代码解释成可以在网页中实现的工具。
5.1 加载优化
5.1.1 defer
该属性可以等待 DOM 加载完毕后再去加载脚本,可以避免因外部文件过大或网络卡顿导致文件阻塞。
例子:
// 从外部引入一个死循环的 js 代码
<script src="js/01.js" defer></script>
<script>
console.log("哈哈哈");
</script>
如果不使用 defer
属性,则会出现死循环导致 哈哈哈
无法被打印出来,使用 defer
后可以先输出內容,再加载外部脚本。
5.1.2 async(推荐使用)
- 作用:该属性可以使 DOM 加载和 JS 脚本加载异步执行,从而同时进行。
- 优点:避免因 DOM 文件过大导致的 文件加载阻塞。
- 缺点:无法确定 JS 脚本到底何时执行,并仅对外部 JS 脚本有效。
例如:
<script src="js/01.js" async></script>
<script src="js/02.js" async></script>
console.log("页面内部的脚本");
按照我们的说法,引入的两个 JS 脚本和本地的 DOM 是异步执行的,也就是说究竟先输出那句是不一定的,但是事实却不是这样。
注意:由于 HTML5 规范要求,脚本执行应该按照脚本出现的先后顺序执行,所以应该是先输出页面内部的脚本,然后是01.js 中的内容,然后是 02.js 里的内容。
5.2 性能优化
5.2.1 重绘(repaint)与回流(reflow)
重绘:当页面的可见性发生变化时,我们说页面发生了重绘。
回流:当页面中的部分(全部)元素改变宽度和高度,或者位置发生变化,删除或增加某个(某些元素)、某个元素隐藏或显示时,这时页面的重新加载被称为回流。
总结:回流必将引起重绘,但是重绘不一定会引起回流。
注意:
- 重绘的代价是高昂的,因为浏览器必须验证 DOM 树上其它元素节点的可见性。
- 回流更是浏览器性能的关键,因为其变化设计到页面的布局。一个元素的回流导致了其所有子元素以及 DOM 中紧随其后的祖先元素的随后的回流。
5.2.2 重绘和回流的原因
- 调整窗口大小
- 改变字体
- 增加或者移除样式表
- 用户在
input
框中输入文字 - 激活 CSS 伪类
- 操作
class
属性 - 脚本操作 DOM
- 计算
offsetWidth
和offsetHeight
- 设置
style
属性的值
5.2.3 如何从重绘和回流方面提高浏览器性能
- 不要打断修改样式的过程,例如在修改样式时创建新元素
- 读写 DOM 尽量放在一起,避免一会读一会写
- 将创建的内容添加到文档碎片
var fragment = document.createDocumentFragment();
中,然后统一进行添加 - 使用
fixed
或absolute
可减少回流和重绘 - 使用如下方式把发生重绘的代码推迟到下一次重绘发生时一起执行
window.requestAnimationFrame(function() { for (var i = 0; i < div.length; i++) { div[i].style.backgroundColor = "red"; } })
6.window.history
window.history
对象表示整个浏览器的页面栈对象。在对象中提供了一些属性和方法更好的控制整个浏览器中页面的访问。
6.1 back()
跳转到栈中的上一个页面
6.2 forward()
跳转到栈中的下一个页面
6.3 go(num)
指定跳转的页面个数
6.4 length
栈中页面的数量
注意:使用 window.history
对象中提供的方法进行的页面跳转并不会向栈中添加新的页面,而通过 window.location.href
或者通过 a
标签进行跳转,则会向栈中添加新的页面。