はじめに
Reactの学習でJavaScriptを書いていたときに document が出てきました。そういえば、自分でインスタンス化していないのに、なぜメソッドを使えるのだろうと気になりました。そこで、Documentオブジェクトがどこで定義されていて、いつインスタンス化されているのか、そもそもDOMとは何かを調べてみました。macOSとChromeを前提にしています。
結論
DocumentオブジェクトのクラスはChromeのソースコードで定義されていて、インスタンスはChromeがページを開くたびに作っています。作られたインスタンスは window.document としてグローバルに置かれるため、自分で new しなくても document のメソッドを使えます。
また、DOM(Document Object Model)は、HTMLをオブジェクトの木構造として表し、JavaScriptから操作できるようにする仕組みのことです。(参考)Chromiumのソースコードにも dom というフォルダがありました。
根拠
1. DocumentクラスはChromeが用意したものか
関数(クラス)の toString() は、その関数のソースコードを文字列で返します。ただし、ブラウザやJavaScriptエンジンが最初から用意している関数は、返せるJavaScriptのソースコードが無いため、代わりに [native code] と表示されます。(参考)
Document で [native code] が表示されるか確認します。
Document.toString()
// 出力:'function Document() { [native code] }'
これで分かるのは、ページのJavaScriptではなくブラウザ側が用意したものだという点までです。何の言語で書かれているかは、5で確認します。
2. document は Document クラスのインスタンスか
instanceof で、document が Document クラスのインスタンスか確かめます。
インスタンスの場合、true が出力されます。
document instanceof Document
// 出力:true
3. ページを開くたびにDocumentクラスのインスタンスを作っているか
再読み込みすると、それまでの変数も全部消えるため、前後の document を直接比べることはできません。そこで、document に独自のプロパティを追加して文字列を入れておき、再読み込み後にそのプロパティが undefined になることを確認します。
document.myMark = "before"
document.myMark // 出力:'before'
// 再読み込み
document.myMark // 出力:undefined
document instanceof Document // 出力:true
再読み込み後の document には目印が無いので、前とは別のオブジェクトです。それでも Document クラスのインスタンスなので、読み込みのたびに新しいインスタンスが作られていると分かります。
4. window.document がグローバルに置かれているか
1行目で、window がグローバルオブジェクト(どこからでも名前だけで呼べる変数の置き場)であることを確認します。2行目で、名前だけで書いた document が window.document と同じものであることを確認します。
globalThis === window // 出力:true
window.document === document // 出力:true
5. documentとDOMはどこで見られるか
PCにインストールされているChromeは、Googleが配布前にコンパイル(機械語に変換)したものなので、中のソースコードは見られません。ですが、ChromeはオープンソースのChromiumをベースに作られているので、Chromiumのリポジトリで確認できます。
Documentの定義には、Web IDL と C++ が使われています。
Web IDL とは
IDL は Interface Definition Language(インターフェース定義言語)の略です。処理は書かず、JavaScriptからどんな名前・型で使えるかだけを宣言する言語で、拡張子は .idl です。
C++ の拡張子
.h はクラスなどの宣言を書くファイルの拡張子で、.cc はその宣言をincludeして処理の中身を書くファイルの拡張子です。
Chromiumのリポジトリ
DOM周りのフォルダ構成
Documentオブジェクトの定義ファイル
https://github.com/chromium/chromium/blob/main/third_party/blink/renderer/core/dom/document.idl
https://github.com/chromium/chromium/blob/main/third_party/blink/renderer/core/dom/document.h
https://github.com/chromium/chromium/blob/main/third_party/blink/renderer/core/dom/document.cc
さいごに
これ以上調べ続けると沼にハマりそうだったので、ここで止めます。
ここまででも、気になっていた点は解消されました。ChromeがChromiumをベースに開発されていることや、Web IDL と C++ で書かれていることも知れて、documentやDOMの理解が少し深まって良かったと感じています。
