元々DOM(Document Object Model)は、W3Cによって策定された、XML文書をプログラムから操作する為のインターフェイスでした。
最新のDOMは、WHATWGにより策定され、実際にアプリケーションを作成するために必要な機能の、包括的なインターフェイスとなっています。
W3CのDOMでは触れられることが無かった、Windowオブジェクトに関してもインターフェイスが決められています。
おかげで、Webブラウザによる違いを吸収する労力が激減して、アプリケーションの開発に注力できるようになりました。
実際の仕様は、WHATWGにより策定された『DOM Living Standard』と、その『非公式な日本語訳』にあります。興味が有ればご覧ください。
DOMで何かをする場合、対象となる要素(エレメント)を見つけなければなりません。このためのメソッドがいくつか用意されています。
下のボタンをクリックしてください。ボタンに記載されているコードに該当する要素に色がつきます。
["id_004"].childrenは、id_004の要素のchildrenフィールドと解釈してください(以下全て同じです)。
枠線で囲った7つの要素が対象です。全ての要素がDIVで、中のテキストがid属性とclass属性の内容です。
idがid_001の要素の子要素がid_002とid_003、id_004の要素の子要素がid_005とid_006になります。
idがid_007の要素は、id_005の子要素でid_004の孫要素になります。
最初の3つ(document.getElementById・document.getElementsByTagName・document.getElementsByClassName)は、W3CのDOMにも存在するメソッドです。
引数のIDに該当する要素を返します。
HTML文書では、id属性がユニークと決められているので、返却される要素は必ず1つです。
引数のタグ名称に該当する要素を返します。
該当する全ての要素を、NodeListとして返します。JavaScriptでは、返却値を配列として扱うことができます。
引数のクラス名称に該当する要素を返します。
該当する全ての要素を、NodeListとして返します。JavaScriptでは、返却値を配列として扱うことができます。
WHATWGのDOMで追加されたNodeオブジェクトのフィールド(DOMの仕様書では属性)です。
指定要素の全ての子要素です。子要素なので、孫要素の["id_007"]は対象外です。
W3CのDOMにも、よく似たフィールドNode.childNodesがありましたが、致命的な問題があり使い難いものでした(詳細は『ご注意(其の壱)』を参照してください)。
このフィールドのおかげで、随分楽になりました。
WHATWGのDOMで追加されたNodeオブジェクトのフィールドです。
指定要素の最初の子要素です。
W3CのDOMにも、よく似たフィールドNode.firstChildがありましたが、致命的な問題があり使い難いものでした(詳細は『ご注意(其の壱)』を参照してください)。
このフィールドのおかげで、随分楽になりました。
指定要素の最後の子要素です。
WHATWGのDOMで追加されたNodeオブジェクトのフィールドです。
W3CのDOMにも、よく似たフィールドNode.lastChildがありましたが、致命的な問題があり使い難いものでした(詳細は『ご注意(其の壱)』を参照してください)。
このフィールドのおかげで、随分楽になりました。
WHATWGのDOMで追加されたNodeオブジェクトのメソッドです。
引数は、CSSのセレクターです。
CSSと同じパターンマッチの規則で、該当する要素を返します。複数該当した場合は、先頭の要素を返します。
このメソッドには少々問題があります。『ご注意(其の弐)』を参照の上、使用の可否を判断してください。
可能な限り、他のメソッドやフィールドの使用を考慮してください。
WHATWGのDOMで追加されたNodeオブジェクトのメソッドです。
引数は、CSSのセレクターです。
CSSと同じパターンマッチの規則で、該当する要素を全て返します。
このメソッドには少々問題があります。『ご注意(其の弐)』を参照の上、使用の可否を判断してください。
可能な限り、他のメソッドやフィールドの使用を考慮してください。
querySelectorAllは、特定の要素から呼ぶことで、その要素の子孫だけを対象にすることができます。
この例では、["id_001"]から呼び出しているので、対象はその子孫だけです。
["id_001"]の子孫にはcls_200をclassに設定している要素がないので、対象は["id_005"]だけとなります。
このメソッドには少々問題があります。『ご注意(其の弐)』を参照の上、使用の可否を判断してください。
可能な限り、他のメソッドやフィールドの使用を考慮してください。
W3CのDOMに於けるNode.childNodes・Node.firstChild・Node.lastChildは、あくまでもNodeを対象としているので、返却値が要素(Element)とは限りません。
次のようなHTMLがあるとします。
<div id="id_01">
<div id="id_02"></div>
<div id="id_03"></div>
</div>
idがid_01の要素の開始タグの後ろには改行があり、idがid_02の要素の開始タグの前には空白があります。
これは、id_01要素の最初の子要素が、テキストノードであることを意味します。
そのため、["id_01"].firstChildは、テキストノードを返します。["id_01"].lastChildも同様です。
["id_01"].childNodesは、[テキストノード,["id_02"],テキストノード,["id_03"],テキストノード]を返します。
W3CのDOMしか使えないような環境では、注意してください。
とっても遅いです。
下の表は、3000の要素を持つドキュメントから、各メソッドを使って、該当の要素を呼び出し回数行の回数、繰り返し抽出した時の、経過時間です。
例えば一番左の列は、getElementByIdを、1億回繰り返し呼び出したときに、何ミリ秒かかったかということです。
繰り返し回数がそれぞれのメソッドで異なるのは、同じ回数では到底テストできないレベルの違いがあるからです。
テストを行ったメソッドと引数は、以下のとおりです。
document.getElementById('id_10599');
document.querySelectorAll('#id_10599');
document.getElementsByClassName('CLS2_200');
document.querySelectorAll('.CLS2_200');
| IDによる検索 | ClassNameによる検索 | |||
|---|---|---|---|---|
| getElementById | querySelectorAll | getElementsByClassName | querySelectorAll | |
| 呼び出し回数 | 100000000回 | 1000000回 | 1000000回 | 10000回 |
| Firefox | 92 | 618.6 | 2 | 260 |
| Google Chrome | 3949.6 | 676.6 | 7.4 | 231.4 |
| Microsoft Edge | 18980.2 | 17146.2 | 684.6 | 218.6 |
結果は、同じテストを5回実施した平均です。
テストは、Linuxの仮想環境で動作する、Windows10の32ビット版で行っています。ディスクIOやネットワーク通信による影響は無いので、通常の環境と大きく異なることは無いと思います。
Firefoxの場合、getElementByIdとquerySelectorAllでは、600倍以上、querySelectorAllの方が遅いことになります。
getElementsByClassNameとquerySelectorAllでは、1万倍以上、querySelectorAllの方が遅いことになります。
呼び出し回数が異なるので、到底厳密なテストとは言えませんが、遅いということは感じられたのではないでしょうか?
当コンテンツは、以前より公開している『DOMによるエレメントの操作』というコンテンツの、前半部分を新しい仕様を元に改訂したものです。
旧版では、仕様書のIDLなども記載していましたが、大幅な仕様改定もあり、新版ではIDLの記載は取りやめました。
『DOMによるエレメントの操作』の後半と、『DOMによるスタイルの操作』の内容は、次のコンテンツである『DOMにより、エレメントを変化(へんげ)させる』で、改定したものを公開しています。