我們知道,DOM(文檔對象模型)是為了操作文檔而定義的一組接口,而BOM(瀏覽器對象模型)則是為了操作瀏覽器而定義的一組接口。這很好理解,通過命名就能知道。真正有意思的地方在于,基于JavaScript的“對象系統”(《淺析JavaScript的對象系統》),我們似乎只通過一個對象就能拿到我們需要的幾乎所有東西,原生函數、自定義函數、全局變量、DOM、瀏覽器屬性。。。沒錯,這個“包羅萬象”的對象就是——window
。
document
是DOM的核心對象,window
則是BOM的核心對象,而又有:
console.log(window.document === document); //true
因為document
是DOM的根節點,而以上代碼又表明:document
在window
對象中是作為其一個屬性而存在的,因此從這個角度來說,BOM包含了DOM。與此類似,你還可以驗證如下代碼:
console.log(window.location === location); //true
console.log(window.navigator === navigator); //true
console.log(window.screen === screen); //true
console.log(window.history === history); //true
console.log(window.window === window); //true
location
navigator
screen
history
和window
一樣,都是BOM提供的對象,只不過它們和document
對象一樣,都同時以屬性的形式存在于window
中。上面的測試似乎有些多此一舉,但為了驗證window
作為“根”的角色,這些測試都是有意義的。
當你在瀏覽器中console.log(window)
,你應該能大體歸納出其構成如下圖:
可以看到,window
可不僅僅是BOM中的那個瀏覽器窗口對象而已,它實際上包含了某個頁面所在的窗口中與JavaScript相關的方方面面。但是,我們明明說“window是BOM的核心對象”啊,BOM本身只提供對瀏覽器的操作接口,從這個角度來說,window
跟與瀏覽器窗口無關的那些什么原生構造函數、全局變量/函數有半毛錢關系?為什么它們會存在于window
當中?實際上:
ECMAScript 雖然沒有指出如何直接訪問 Global 對象,但 Web 瀏覽器都是將這個全局對象作為 window 對象的一部分加以實現的。—— 《JavaScript高級程序設計(第3版)》
也就是說,Global對象被整個整合進了window
,這才使得后者同時擁有了BOM和Global。
下面我們先拋開這個大大的window
,把范圍縮小,來梳理一下BOM。
window —— 瀏覽器窗口
從BOM的角度來看window
,它瞬間就Low了不少。此時window
表示的就是一個瀏覽器窗口對象,強調的是“瀏覽器窗口”。下圖是對其的整理歸納,列出了大部分常用的屬性和方法。其中亮黃色部分是我們實際開發中經常會用到的,相關使用細節自行測試實踐即可,并不難,這里不再詳述。
location —— 頁面URL
navigator —— 瀏覽器信息
不同瀏覽器提供的navigator
對象支持的屬性差別不小,而且有些屬性的結果并不盡如人意,比如幾乎所有瀏覽器的navigator.appCodeName
的結果都為Mozilla
,這似乎難以理解。因為這些原因,navigator
對象并不是很常用,盡管各瀏覽器為該對象提供的屬性并不少。檢測瀏覽器類型和版本就需要通過navigator
對象,具體如何操作請自行了解。
screen —— 顯示器屏幕
不同瀏覽器中的screen
對象也都包含著不同的屬性,具體請自行Google。screen
對象極少用到,了解即可。
history —— 瀏覽歷史記錄
可能到這里,你還不是很清楚window
和BOM之間的關系。其實說白了就是:window
是BOM的核心對象,但同時,window
又是ECMAScript中的Global對象的超集。也就是說,在瀏覽器中window
有著雙重角色,我們可以分別從BOM(瀏覽器)和Global(ECMAScript)兩個角度去理解。
最后,上一張完整的圖: