1.什么是 BOM
BOM(Browser Object Model)即瀏覽器對象模型。
關于 BOM 的說明:
- BOM 提供了獨立于內容,而與瀏覽器窗口進行交互的對象。
- 由于 BOM 主要用于管理窗口和窗口之間的通訊,因此其核心對象是
window對象。 - BOM 由一系列相關的對象構成,并且每個對象都提供了很多方法與屬性。
- BOM 缺乏一個統(tǒng)一的標準:
- JavaScript 語法的標準組織是 ECMA
- DOM 的標準組織是 W3C(所有瀏覽器公共遵守的標準)。
- BOM 是各個瀏覽器廠商根據(jù) DOM 在各自瀏覽器上的表現(xiàn)(表現(xiàn)為不同瀏覽器定義有差別,實現(xiàn)方式不同)。
注意:通常情況下如果提到 BOM,一般指的都是 window 對象。
2.BOM 和 DOM 之間的關系
可以認為 BOM 是瀏覽器窗口,DOM 則是瀏覽器窗口中的頁面。
總結:
- DOM 通過
document對象來訪問、控制、修改 html 和 xhtml 等文檔中的內容。 - BOM 通過
window對象來訪問、控制、修改瀏覽器中的內容。 - 聯(lián)系:
- BOM 包含 DOM,瀏覽器提供用來訪問的是 BOM 對象,從 BOM 對象可以訪問到 DOM 對象,從而使 JavaScript 可以操作瀏覽器,并通過操作瀏覽器讀取到文檔的內容。
- 區(qū)別:
- DOM 描述了處理網(wǎng)頁內容的方法和接口,即操作頁面內部。BOM 描述了與瀏覽器進行交互的方法和接口,即操作頁面之間。
3.window 對象
window 對象是 BOM 的具體表現(xiàn)形式。window 和 BOM 之間的關系就像 document 和 DOM 之間的關系一樣,BOM 相當于 DOM,window 相當于 document。
注意:因為 window 對象是 JS 中的頂級對象,因此所有定義在全局作用域中的變量、函數(shù)都會變成 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 屬性擁有在不同頁面依舊存在的特性,因此出現(xiàn)了一門叫做 跨域傳輸 的技巧。而這個技巧的內部實現(xiàn)原理就是 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返回頁面滾動的距離(通用),這兩個屬性指的是頁面發(fā)生滾動的距離。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 瀏覽器的信息,在檢測瀏覽器及操作系統(tǒng)上非常有用。(這個對象和 event一樣,是全局并且唯一的。)
navigator.appCodeName // 瀏覽器代碼名的字符串表示
navigator.appName // 官方瀏覽器名的字符串表示
navigator.appVersion // 瀏覽器版本信息的字符串表示
navigator.cookieEnable // 如果啟用 cookie 返回 true,否則返回 false
navigator.javaEnable // 如果啟用 java 則返回 true,否則返回 false
navigator.platform // 瀏覽器所在計算機平臺的字符串表示
navigator.plugins // 安裝在瀏覽器中的插件數(shù)組
navigator.userAgent // 返回和瀏覽器內核相關的信息(加粗)
注意:如果 window.navigator.userAgent 出現(xiàn)了 Mobile,則可以確定用戶使用的是移動設備。
3.2 window 對象中涉及的其它方法
3.2.1 alert
alert 是一個警示框,作用是提示用戶信息,該方法執(zhí)行后無返回值。
語法:
window.alert("Hello World!");
// 或
alert("Hello World!");
注意:警示框彈出后將阻斷程序執(zhí)行,必須關閉警示框程序才會繼續(xù)執(zhí)行。
3.2.2 prompt
prompt 也表示警示框,作用是提示用戶信息,該方法執(zhí)行后根據(jù)情況不同返回值略有不同。
- 點擊取消:返回
null - 沒有默認值:
如果用戶沒有輸入內容,返回一個空字符串。
如果用戶輸入了內容,返回值為用戶輸入的內容。 - 有默認值
如果用戶沒有輸入內容,返回默認值
如果用戶輸入了內容,返回值為用戶輸入的內容。
語法:
// 默認值不是必須的
var res = prompt(msg, defaultMsg);
3.2.3 confirm
confirm 表示警示框,作用是提示用戶信息,點擊確認返回 true,點擊取消返回 false。
語法:
var msg = window.confirm("我是 confirm");
console.log(msg);
注意:以上三種對話框都是模式對話框,即在用戶點擊確定按鈕或者取消按鈕把對話框關閉之前,它將阻止用戶對瀏覽器的所有輸入,并暫停對 JavaScript 代碼的執(zhí)行,在用戶做出響應之前,不會執(zhí)行下一條語句。
3.2.4 間隔調用和延遲調用
-
使用間隔調用
setInterval方法用于實現(xiàn)間隔調用,又被稱為定時器。是一種能夠每隔一定時間自動執(zhí)行一次的函數(shù)。
語法:var timer = null; timer = setInterval(function() { console.log("hello"); }, 1000);以上代碼會每隔 1s 打印一次 hello,所以
function代表的是要被回調的函數(shù),1000 代表的是函數(shù)調用的時間間隔。如果間隔調用的函數(shù)需要傳入?yún)?shù),則間隔調用需要使用如下的聲明方式。
語法:var timer = null; timer = setInterval(字符串, 執(zhí)行事件的時間間隔 ms);例如:
var timer = null; function show(words) { console.log(words); } var timer = setInterval('show("hello")', 1000);注意:
- 間隔調用不是立即執(zhí)行,而是在 任務隊列中的任務完成后 才執(zhí)行間隔調用。
- 因為間隔調用函數(shù)的實際執(zhí)行者是
window,因此間隔調用內部的this指向window。
-
移除間隔調用
clearInterval方法用于移除間隔調用
語法:clearInterval(timer);上述代碼能夠將剛才創(chuàng)建的定時器移除掉。
注意:間隔調用的返回值是一個數(shù)字隊列,因此通過訪問數(shù)字隊列來清除間隔調用也是被允許的。
例如:setInterval(function() { console.log("hello"); }, 1000); setTimeout(function() { clearInterval(1); }, 5000); -
延遲調用
延遲調用又叫延遲調用函數(shù)。是一種能夠等待一定事件后再去執(zhí)行的函數(shù)。
語法:var timer = null; timer = setTimeout(需要執(zhí)行的函數(shù), 等待的時間);例如:
var timer = setTimeout(function() { clearInterval(1); }, 5000);上面代碼的功能是在頁面加載 5s 后清除定時器。
4.數(shù)據(jù)解析
數(shù)據(jù)解析是指將 不能被直接打開的數(shù)據(jù) 通過某種方法轉變?yōu)?能夠被直接使用的數(shù)據(jù)。
對于開發(fā)者來說最常見的數(shù)據(jù)解析就是將 字符串數(shù)據(jù) 解析為 對象數(shù)據(jù)。
例如:
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.頁面加載優(yōu)化和 JS 文件解析順序
在閱讀下面的內容之前,先了解一下 JavaScript 引擎這個概念。
JS 引擎是由渲染引擎和解釋器構成。
-
渲染引擎
- 解析代碼:HTML 代碼解析為 DOM 樹
- 對象的合成:CSS 和 DOM 合成一棵渲染樹
- 布局:計算出渲染樹的布局
- 繪制:將渲染樹繪制到屏幕
注意:這四步不一定嚴格按照順序來執(zhí)行。
JS 解釋器
能夠將 JS 代碼解釋成可以在網(wǎng)頁中實現(xiàn)的工具。
5.1 加載優(yōu)化
5.1.1 defer
該屬性可以等待 DOM 加載完畢后再去加載腳本,可以避免因外部文件過大或網(wǎng)絡卡頓導致文件阻塞。
例子:
// 從外部引入一個死循環(huán)的 js 代碼
<script src="js/01.js" defer></script>
<script>
console.log("哈哈哈");
</script>
如果不使用 defer 屬性,則會出現(xiàn)死循環(huán)導致 哈哈哈 無法被打印出來,使用 defer 后可以先輸出內容,再加載外部腳本。
5.1.2 async(推薦使用)
- 作用:該屬性可以使 DOM 加載和 JS 腳本加載異步執(zhí)行,從而同時進行。
- 優(yōu)點:避免因 DOM 文件過大導致的 文件加載阻塞。
- 缺點:無法確定 JS 腳本到底何時執(zhí)行,并僅對外部 JS 腳本有效。
例如:
<script src="js/01.js" async></script>
<script src="js/02.js" async></script>
console.log("頁面內部的腳本");
按照我們的說法,引入的兩個 JS 腳本和本地的 DOM 是異步執(zhí)行的,也就是說究竟先輸出那句是不一定的,但是事實卻不是這樣。
注意:由于 HTML5 規(guī)范要求,腳本執(zhí)行應該按照腳本出現(xiàn)的先后順序執(zhí)行,所以應該是先輸出頁面內部的腳本,然后是01.js 中的內容,然后是 02.js 里的內容。
5.2 性能優(yōu)化
5.2.1 重繪(repaint)與回流(reflow)
重繪:當頁面的可見性發(fā)生變化時,我們說頁面發(fā)生了重繪。
回流:當頁面中的部分(全部)元素改變寬度和高度,或者位置發(fā)生變化,刪除或增加某個(某些元素)、某個元素隱藏或顯示時,這時頁面的重新加載被稱為回流。
總結:回流必將引起重繪,但是重繪不一定會引起回流。
注意:
- 重繪的代價是高昂的,因為瀏覽器必須驗證 DOM 樹上其它元素節(jié)點的可見性。
- 回流更是瀏覽器性能的關鍵,因為其變化設計到頁面的布局。一個元素的回流導致了其所有子元素以及 DOM 中緊隨其后的祖先元素的隨后的回流。
5.2.2 重繪和回流的原因
- 調整窗口大小
- 改變字體
- 增加或者移除樣式表
- 用戶在
input框中輸入文字 - 激活 CSS 偽類
- 操作
class屬性 - 腳本操作 DOM
- 計算
offsetWidth和offsetHeight - 設置
style屬性的值
5.2.3 如何從重繪和回流方面提高瀏覽器性能
- 不要打斷修改樣式的過程,例如在修改樣式時創(chuàng)建新元素
- 讀寫 DOM 盡量放在一起,避免一會讀一會寫
- 將創(chuàng)建的內容添加到文檔碎片
var fragment = document.createDocumentFragment();中,然后統(tǒng)一進行添加 - 使用
fixed或absolute可減少回流和重繪 - 使用如下方式把發(fā)生重繪的代碼推遲到下一次重繪發(fā)生時一起執(zhí)行
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)
指定跳轉的頁面?zhèn)€數(shù)
6.4 length
棧中頁面的數(shù)量
注意:使用 window.history 對象中提供的方法進行的頁面跳轉并不會向棧中添加新的頁面,而通過 window.location.href 或者通過 a 標簽進行跳轉,則會向棧中添加新的頁面。