如何理解js高程里的document對象是HTMLDocument的實例?

document節點不是屬於document類型嗎?怎麼還有個HTMLDocument?HTMLDocument是什麼東西?一個原型?


謝邀。

首先要理解的是 DOM 是 API,是一組無關編程語言的介面(Interfaces)而非實現(Implementation)。前端平時常說的 DOM 其實只是瀏覽器通過 ECMAScript(JavaScript)對 DOM 介面的一種實現。

其次要知道的是,DOM 既是為 HTML 制定的,也是為 XML 制定的。而兩者各有一些特異的部分,所以作為 DOM 標準基石的 DOM Level 1 其實分為 Core 與 HTML 兩個部分。Core 定義了 fundamental interfaces 與 extended interfaces,分別是共用的基礎介面與 「XML 拓展包」,而 HTML 部分則全都是「HTML 拓展包」。題主所問到的 Document 介面被定義在 Core 的 fundamental interfaces 中,而 HTMLDocument 介面則定義在 HTML 部分中,且「介面繼承」於 Document。

這種繼承關係當然是可以在 JavaScript 的 DOM 實現中體現出來的:

// document 是 HTMLDocument 的實例
document instanceof HTMLDocument // true

// document 的 [[prototype]] 指向 HTMLDocument 的原型
document.__proto__ === HTMLDocument.prototype // true

// HTMLDocument 偽類繼承於 Document
HTMLDocument.prototype instanceof Document // true
HTMLDocument.prototype.__proto__ === Document.prototype // true

至於 Document 與 HTMLDocument 這兩個構造函數,跟 Array、Object 一樣都是 built-in 的:

&> Document
&< function Document() { [native code] } &> HTMLDocument
&< function HTMLDocument() { [native code] }

雖然是 native code,但一個有意思的現象是,這兩個構造函數之間也是存在原型鏈的:

// HTMLDocument 的 [[prototype]] 是指向 Document 的
HTMLDocument.__proto__ == Document

// 同理
Document.__proto__ == Node
Node.__proto__ == EventTarget

其作用是實現對靜態成員的繼承。( ES6 Class 的行為與此完全一致,但這個行為在更早之前就是這樣了。)

好了扯遠了,總結一下,在 JavaScript 的 DOM 實現中

  • document 是 HTMLDocument 的實例
  • HTMLDocument 繼承於 Document

留一個課後作業,有興趣的話可以看看 Document.prototype 與 HTMLDocument.prototype 里分別都有什麼?在不同瀏覽器里都試試。

以上。


HTMLDocument 介面提供了對 HTML 層級的訪問。

HTMLDocument 介面對 DOM Document 介面進行了擴展,定義 HTML 專用的屬性和方法。

document 對象的 prototype 為 HTMLDocument 對象,HTMLDocument 對象的 prototype 為 Document 對象。

可以試下:

console.log(Object.getPrototypeOf(document));

console.log(Object.getPrototypeOf(Object.getPrototypeOf(document)));

看看輸出什麼。


function Cat(){this.type="animal"};

cat = new Cat();

我們一般稱Cat是一個類,cat是類的實例。

document是 HTMLDocument類的實例。DOM Document類型就相當於cat實例的type屬性中的一種。

以上就解釋了你的問題。

其實瀏覽器中有很多類的,你用document.getElementById獲取到的段落 或者a標籤,都是一個類的實例,比如li列表就是HTMLLIElement的實例。

說到這裡,你可以打開chrome瀏覽器的開發者工具,在element標籤的右邊,找到propertie小標籤(緊挨著調試樣式的styles),你就可以看到選中的元素的原型鏈。(在左邊選擇元素,右邊就能直觀看到原型鏈了)

你或許會看到什麼Element,Node類。接下來你需要理解到JavaScript中的原型鏈,怎麼實現繼承的。就去問原型鏈的東西吧。例如我問你一個對象的原型鏈中有EventTarget類,說出這個對象可以做什麼。

還有個辦法就是找到typescript的lib.es6.d.ts(如果你用visual studio code,你在js中按住ctrol點擊任意一個build-in方法就能跳轉到)。這個文件也可以看到繼承關係,介面啊什麼都有。你可以查到某一個api是來自哪一個類的。比如我問你insertAdjacentElement這個方法來自哪一個類?有哪些類能夠使用這個方法,為什麼document上沒有這個方法?Node和Element還有HTMLElement的區別。這個文件只能作為方言的參考,具體的實現得看V8的C++代碼。


推薦閱讀:

TAG:前端開發 | JavaScript | 編程 | 前端工程師 | DOM |