🌐

【超ザックリ・図解付き解説】JavaScriptのDOM

2022/12/12に公開1

はじめに

今回の記事では、JavaScriptで重要な概念であるDOMについてザックリ解説する。簡単に言えば、DOM(Document Object Model)は、HTMLの要素を操作するための仕組みのことである。

前提として、公式ドキュメントがあるのでDOMを他のネット記事で調べる必要はないと思うだろう。しかし、DOMはJavaScriptにおいて重要な概念であるにもかかわらず、それを正しく説明できる人は少ない。

これに関連して、Zennの記事「何度調べてもわからないDOMに決着をつける」では、DOMについて以下のように述べている。

そして、DOM(というよりJavaScript)の恐ろしいところは、理解していなくてもコピペなどで何となく結果が返ってくることです。

プログラミングの世界では、上述の引用のように「理解していなくてもコピペなどで何となく結果が返ってくる」ことは珍しくない。このような状態で学習・開発を進めていくと、何らかのエラーに躓いた時に対応できなくなることが考えられる。

そこで、今回の記事では図解付きでDOMについて解説する。本記事は学習・開発によくある「仕組みはわからないが、とりあえず動いた」という状態を少しでも解消するために書いた。本記事が少しでもJavaScriptのDOMについて理解を深める契機になれば非常に幸いである。

DOMとは?

概要

DOMは、公式ドキュメントによると以下のように定義されている。

The Document Object Model (DOM) is a programming API for HTML and XML documents. It defines the logical structure of documents and the way a document is accessed and manipulated.
(中略)
With the Document Object Model, programmers can create and build documents, navigate their structure, and add, modify, or delete elements and content. Anything found in an HTML or XML document can be accessed, changed, deleted, or added using the Document Object Model, with a few exceptions - in particular, the DOM interfaces for the internal subset and external subset have not yet been specified.

引用部分の日本語訳

Document Object Model(DOM)は、HTMLまたはXML文書のためのプログラミングAPIです。ドキュメントの論理構造と、ドキュメントへのアクセスや操作の方法を定義しています。

(中略)

Document Object Model を用いることで、プログラマーは文書を作成・構築し、その構造を閲覧し、要素や内容を追加・変更・削除することができます。HTMLやXML文書にあるものはすべて、Document Object Modelを使ってアクセス、変更、削除、追加することができます。特に、内部サブセットと外部サブセットのDOMインターフェースはまだ規定されていません。

公式ドキュメントによると、DOM(Document Object Model)とはHTML、あるいはXMLドキュメントに関連するAPIで、ドキュメントの構造や操作を定義したものを意味する。DOMを使うことで、私たちプログラマーは文書を作成したり、閲覧したり、要素や内容を追加・変更・削除したりできる。HTMLやXML文書にあるものはすべてDOMを使って操作できる。

DOMをより具体的に述べるとMVCモデルのようなものである。MVCモデルは、MVC Framework - Introduction - Tutorialspointの記事によると、以下のように定義されている。

The Model-View-Controller (MVC) is an architectural pattern that separates an application into three main logical components: the model, the view, and the controller. Each of these components are built to handle specific development aspects of an application. MVC is one of the most frequently used industry-standard web development framework to create scalable and extensible projects.

引用部分の日本語訳

モデル・ビュー・コントローラー(MVC)は、アプリケーションをモデル、ビュー、コントローラーの3つの主要な論理コンポーネントに分離するアーキテクチャパターンです。これらのコンポーネントはそれぞれ、アプリケーションの特定の開発局面を処理するために構築されています。MVCは、拡張性のあるプロジェクトを作成するために、最も頻繁に使用される業界標準のWeb開発フレームワークの1つです。

要は、MVC(Model-View-Controller)モデルとはアプリケーションをモデル(Model)、ビュー(View)とコントローラ(Controller)の三つのロジックに分離するアーキテクチャ[1]を意味する。

ただし、MVCモデルはアプリケーションをModel、View、Controllerの三つに分割するという定義があるだけで実態はない。プログラマーがその定義に従って構築し、その構築したものも同様にMVCモデルと呼ばれる。DOMも同じで実態はいない。定義されたとおりに実装すると、それもDOMと呼ばれる。

DOMが定義しているもの

それでは、DOMは一体何を定義しているのだろうか?それはインターフェイスである。DOMでは、HTMLあるいはXMLドキュメントの各構成要素をオブジェクトに変換する。そして、この定義されたインターフェイスを実装して、そのオブジェクトを操作できるようにする。

更に、DOMはプログラムが文書の構造、スタイルや内容を変更できるように、ページを表現する。DOMは文章をノードとオブジェクトとして表現し、プログラミング言語がページと相互作用できるようにする。

Webページのドキュメントは、ブラウザのウィンドウに表示されるが、HTMLソースとして表示されるかのどちらかに該当する。両方とも同じ文書だが、DOM表現で操作できる。DOMはJavaScriptなどのようなスクリプト言語で変更できる。

/*
paragraph[0] => 最初の<p>要素
paragraph[1] => 二番目の<p>要素
*/
const paragraphs = document.querySelectorAll('p')

alert(paragraphs[0].nodeName)

例えば、上述のコードのquerySelectorAll関数はDOMでドキュメント内のすべての<p>要素のリストを返す必要があると指定されている。

DOMを使って実装されている主な代表例がWebブラウザである。Webブラウザは、その定義をもとにインターフェイスを実装している。WebブラウザはHTMLを読み込むと、そのHTMLの各構成要素をそれらに該当するインターフェイスを実装して、それぞれをオブジェクト化する。このようにしてDOMが完成する。

そして、ドキュメントを画面に表示する際にHTMLドキュメントをそのまま解読して表示するのではなく、このDOMをベースに画面を表示する。要は、HTMLドキュメントはデータの取得にだけ使用され、画面を表示したり、その表示を変更したりする処理はDOMで行われる。

DOMの仕組み

MDN Web Docsの記事「Introduction to the DOM - Web APIs|MDN」によれば、DOMの仕組みは以下のように説明されている。

The DOM is built using multiple APIs that work together. The core DOM defines the entities describing any document and the objects within it. This is expanded upon as needed by other APIs that add new features and capabilities to the DOM. For example, the HTML DOM API adds support for representing HTML documents to the core DOM, and the SVG API adds support for representing SVG documents.

引用部分の日本語訳

DOM は複数の API を使って構築されており、それらが連携して動作します。コアとなる DOM は、あらゆる文書とその中のオブジェクトを記述するエンティティを定義しています。これは必要に応じて他の API によって拡張され、DOM に新しい機能と性能を追加します。例えば、HTML DOM API は HTML ドキュメントを表現するためのサポートをコア DOM に追加し、SVG API は SVG ドキュメントを表現するためのサポートを追加しています。

MDN Web Docsによると、DOMの仕組みは以下のように定義されている。

  • 複数のAPIを使って構築されており、それらが連携して動作する
  • コアとなるDOMは、あらゆる文書とその中のオブジェクトを記述するエンティティ[2]を定義している。そのエンティティは、必要に応じて他のAPIによって拡張され、DOMには新しい機能や性能を追加する。

さらに、HTMLは木構造モデル[3]の構造をしているので、それを基に作られるオブジェクトも木構造モデルの関連性にできる。したがって、このオブジェクトはHTMLを構成する各パーツすべてを操作できる。また、この木構造モデルを一般的にDOMツリーと呼ぶ。DOMツリーはHTMLの木構造モデルと非常に類似している。

DOMとJavaScriptの関係性

DOMとJavaScriptはお互いに密接に関連しあっている。DOMはプログラミング言語ではないが、DOMがなければJavaScriptはWebページ、HTMLやSVGなどそれらの構成要素に関するモデルや概念を表現できない

DOMの正体

このように考えると、DOMはJavaScriptの一部であるかのように考える人も少なくないだろう。ところが、DOMはJavaScriptの一部ではない。あくまで、DOMはWebサイトを構築するために使われるAPIにすぎない。これに関連して、MDN Web Docsの記事「Introduction to the DOM - Web APIs|MDN」によればDOMの正体について以下のように書かれている。

The DOM is not part of the JavaScript language, but is instead a Web API used to build websites. JavaScript can also be used in other contexts. For example, Node.js runs JavaScript programs on a computer, but provides a different set of APIs, and the DOM API is not a core part of the Node.js runtime.

The DOM was designed to be independent of any particular programming language, making the structural representation of the document available from a single, consistent API. Even if most web developers will only use the DOM through JavaScript, implementations of the DOM can be built for any language, as this Python example demonstrates:

引用部分の日本語訳

DOM は JavaScript 言語の一部ではなく、Web サイトを構築するために使用される Web API です。JavaScript は他の文脈でも使うことができます。例えば、Node.js はコンピュータ上で JavaScript プログラムを実行しますが、異なる API のセットを提供し、DOM API は Node.js ランタイムの中核部分ではありません。

DOM は、特定のプログラミング言語から独立し、ドキュメントの構造表現を単一の一貫した API から利用できるように設計されています。ほとんどの Web 開発者が JavaScript でしか DOM を使用しないとしても、この Python の例が示すように、DOM の実装はどの言語でも構築することができます。

上述のMDN Web Docsの内容を踏まえると、DOMは特定のプログラミング言語から独立し、ドキュメントの構造表現を単一の一貫したAPIから利用できるように設計されている。

例えば、PythonでもDOMを以下のように実装できる。

import xml.dom.minidom as m

doc = m.parse(r"C:\Projects\Py\chap1.xml")

doc.nodeName # DOM property of document object
p_list = doc.getElementsByTagName("para")

DOMをJavaScriptで操作する理由

前述までDOMの仕組みを説明し、DOMがJavaScript以外のプログラミング言語でも操作できることを説明した。ところが、なぜDOMをJavaScriptで操作するのだろうか?

Zennの記事「何度調べてもわからないDOMに決着をつける」では、これに関して以下のような見解を述べている。

ウェブブラウザのDOMをJavaSctriptで操作するのは、ウェブブラウザがJavaScriptを実装しており、JavaScriptで操作ができるようにDOMを実装しているからです。例えば、ウェブブラウザがPythonを実装してPythonで操作ができるようにDOMを実装すれば、もちろんPythonで操作できます。ただし、そのような特殊なウェブブラウザを開発したとしても、余程のシェアがない限りウェブサービスなどの開発側は、それに合わせて開発を行うことはないでしょう。仮に業界での標準にしようとしても、ただでさえ大変な標準化作業を、別のプログラム言語で策定し直すのは現実的ではありません。このようなことから、ウェブブラウザでのDOMの操作は、長年JavaScriptで行うようになっています。

上述の引用によると、WebブラウザのDOMをJavaScriptで操作する最大の理由はWebブラウザがJavaScriptを実装しており、DOM自体がJavaScriptで操作できるように実装されているからである。

DOMを実際に使用する方法

DOMを使い始めるのに、別に特別なことをする必要はない。ブラウザで実行されるプログラムであるスクリプトと呼ばれるものの中から、JavaScriptで直接APIを使う。

簡単なスクリプト(拡張子が.jsのファイル)を作成すると、インラインの<script>要素であろうと、Webページに含まれていようと、すぐにドキュメントやウィンドウオブジェクトのAPIを使って、ドキュメント自体やWebページの様々な要素を操作できるようになる。

<body onload="console.log('Hello JavaScript');"></body>

MDN Web Docsの記事「Introduction to the DOM - Web APIs|MDN」によれば、ページの構造(いわゆるHTML)とDOMの操作を混在させることは推奨されない。そのため、以下のコードのようにJavaScriptとHTMLを分離して記述する。

以下のコードでは、次の関数は新しく<h1>要素を作成し、その要素にテキストを追加してドキュメントのツリーに追加する。

<html lang="en">
  <head>
    <script>
      // ドキュメントがロードされる時にこの関数が実行される
      window.onload = () => {
        // 空のHTMLページにいくつかの要素を作成する
        const heading = document.createElement("h1");
        const headingText = document.createTextNode("Big Head!");
        heading.appendChild(headingText);
        document.body.appendChild(heading);
      };
    </script>
  </head>
  <body></body>
</html>

基本的なインターフェイス

本章では、DOMで用いられる基本的なインターフェイスをいくつか紹介する。

インターフェイス 説明
Document ブラウザに読み込まれたあらゆるWebページ。Webページのコンテンツである DOM ツリーへの入口として機能する。
Node 他の多くのDOM APIオブジェクトのページとなる抽象的な基本クラス。
Element Documentに含まれるすべての要素オブジェクトが継承する最も一般的な基底クラス。
NodeList Nodeのコレクション。原則、Node.childNodesなどのプロパティやdocument.querySelectorAll()などのメソッドで返される。
Attr 要素の属性の1つをオブジェクトとして表示する。**Attribute**の略称。
NamedNodeMap Attrオブジェクトのコレクションを意味する。NodeListの最大の違いは、配列のようにインデックスでアクセスできるものの、特定の順序にならないこと。

おわりに

DOMはオブジェクト指向と同様に、ほとんどのプログラマーが使用している割には、結局いまいち理解できていない技術の代表格とも言える。更に、jQueryやReact、Svelteなどの登場で十分に意味を理解できないまま構築を進めている人も少なくないだろう。

本記事が、少しでもDOMを理解する上で参考になれば非常に幸いである。

参考サイト

https://www.w3.org/TR/WD-DOM/introduction.html

https://developer.mozilla.org/en-US/docs/Web/API/Document_Object_Model/Introduction

https://www.tutorialspoint.com/mvc_framework/mvc_framework_introduction.htm

https://zenn.dev/antez/books/6da596a697aa86/viewer/7434bb

https://eng-entrance.com/what-is-dom

脚注
  1. アーキテクチャ(architecture)とは、情報システムの設計方法、設計思想、およびその設計思想に基づいて構築されたシステムの構造などのことである。もともとは、建築学における設計思想や建築様式を意味する専門用語である。参照:IT用語辞典バイナリ ↩︎

  2. エンティティ(entity)とは、実体、存在、実在(物)、本質、本体などの意味を持つ英単語。ITの分野では、何らかの標識や識別名、所在情報によって指し示される、独立した一意の対象物をエンティティということが多い。一つの物事を表現するひとまとまりのデータの集合を意味することが多い。類語にインスタンス(instance)やオブジェクト(object)などが挙げられる。参照:e-words ↩︎

  3. 木構造(tree structure)とは、1つの要素(ノード)が複数の子要素を持ち、子要素が複数の孫要素を持ち、というように階層が深くなるほど枝分かれしていく構造を意味する。木構造を構成する要素をノード(node)と呼び、ノード間のつながりをエッジ(edge)と呼ぶ。参照:e-words ↩︎

GitHubで編集を提案

Discussion

zeropenguinzeropenguin

これまでなんとなくの理解だったので、とても勉強になりました。特に図解で説明してくれるのは分かりやすいですね!