元々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により、エレメントを変化(へんげ)させる』で、改定したものを公開しています。