JavaScript

childNodes is a property that includes all child nodes of an element, including text nodes and comment nodes.

childNodes [property]

childNodesは、特定の要素の子要素を含む NodeList(ノードリスト)を返すプロパティです。NodeListは、配列に似たオブジェクトで、インデックス番号でアクセスできるノードのリストを表します。

 例えば、以下のような HTML要素があった場合に、 childNodesを使って子要素を取得することができます。


<div id="parent">
	<p>First paragraph</p>
	<p>Second paragraph</p>
	<ul>
		<li>Item 1</li>
		<li>Item 2</li>
	</ul>
</div>

 JavaScriptで childNodesを使って子要素を取得するには、以下のようにします。


const parent = document.getElementById('parent');
const cNodes = parent.childNodes;

 この場合、parent変数には id属性が "parent" である div要素が割り当てられ、childNodes変数には parent要素の全ての子要素(p要素、ul要素など)が含まれる NodeListオブジェクトが割り当てられます。

First paragraph

Second paragraph

  • Item 1
  • Item 2

<div id="parent">
	<p>First paragraph</p>
	<p>Second paragraph</p>
	<ul>
		<li>Item 1</li>
		<li>Item 2</li>
	</ul>
</div>

<script>
	const parent = document.getElementById('parent');
	const cNodes = parent.childNodes;
	console.log(cNodes);
</script>

 上記のように、HTMLと JavaScriptを用意してコンソール画面で確認してみました。結果は下図のとおりとなりました。

childNodesの実行画像

 ただし、注意すべき点がいくつかあります。たとえば、childNodesはテキストノードを含むため、NodeListのインデックス番号を使って要素にアクセスする際には、不要なテキストノードを除外するために追加の処理が必要になることがあります。

 また、childNodesは子要素を順番に取得するため、要素の並び順が重要な場合は、childrenプロパティを使う方が便利かもしれません。childrenは、要素の子要素のみを含む HTMLCollectionを返し、テキストノードを含みません。

 childNodesを使って取得した NodeListには、以下のようなメソッドやプロパティがあります。

length

 lengthプロパティは、NodeList内のノードの数を取得します。例えば、上記の例では、上図のコンソール画面にも表示されていますが、parent要素の子要素の数は 7 であるため、childNodes.lengthは 7 となります。


console.log(cNodes.length); // 7

childNodes.lengthの実行画像

item()

 item()メソッドは、指定したインデックスに対応するノードを取得します。インデックスは 0 から始まり、length - 1 までの値を取ることができます。上記の例で考えると lengthが 7 なので、7 - 1 = 6 までの値となります。


console.log(cNodes.item(0)); // #text
console.log(cNodes.item(1)); // <p>First paragraph</p>

childNodesプロパティのitemメソッドの実行画像

 また、インデックスを省略することで、item()メソッドを呼び出すこともできます。この場合、0 が暗黙的に渡されます。


console.log(cNodes[0]); // #text
console.log(cNodes[1]); // <p>First paragraph</p>

childNodesプロパティのitemメソッドを省略した実行画像

forEach()

 forEach()メソッドは、NodeList内の各ノードに対して指定したコールバック関数を実行します。


childNodes.forEach(child => {
	console.log(child.nodeName);
});
// #text
// P
// #text
// P
// #text
// UL
// #text

childNodesプロパティでforEarh()メソッドの実行画像

for...ofループ

 ES6以降のバージョンでは、for...ofループを使用してNodeList内の各ノードにアクセスすることができます。


for (const child of cNodes) {
	console.log(child.nodeName);
}
// #text
// P
// #text
// P
// #text
// UL
// #text

childNodesプロパティでfor...ofループの実行画像

 childNodes は、要素内の全ての子ノード(テキストノード、コメントノード、要素ノード)を含むため、特定の要素だけを取得する場合は、childrenプロパティを使用した方が便利です。


const parent = document.getElementById('parent');
const cNodes = parent.children;
console.log(cNodes);

childrenプロパティの実行画像

 この場合、HTMLCollectionオブジェクトが割り当てられます。HTMLCollectionには forEach()メソッドはありませんが、for...ofループを使用して各要素にアクセスできます。


for (const child of cNodes) {
	console.log(child.nodeName);
}

childrenプロパティでfor...ofループの実行画像

 childNodesを使用する際に注意すべき点がいくつかあります。

テキストノードや空白文字

 childNodesは、テキストノードや空白文字を含むため、要素の子要素のみを取得する場合は、以下のようにフィルタリングする必要があります。


// 要素ノードのみを取得
const elementNodes = [];
cNodes.forEach(child => {
	if (child.nodeType === Node.ELEMENT_NODE) {
		elementNodes.push(child);
	}
});

console.log(elementNodes);

childNodesプロパティでフィルタリングの実行画像

ライブなコレクション

 childNodesは、ライブなコレクションであるため、要素の子要素が変更された場合、自動的に更新されます。

First paragraph

Second paragraph


<div id="parent2">
	<p>First paragraph</p>
	<p>Second paragraph</p>
</div>

<script>
	const parent2 = document.querySelector('#parent2');
	const children = parent2.childNodes;

	console.log(children.length); // 5

	// 要素を追加
	const newP = document.createElement('p');
	newP.textContent = 'New paragraph';
	parent2.appendChild(newP);

	console.log(children.length); // 6
</script>

childNodesプロパティでフィルタリングの実行画像

 この場合、要素を追加すると childNodesに自動的に追加され、lengthプロパティの値が 6 に更新されます。

要素を指定して取得する場合の代替方法

 特定の要素の子要素のみを取得する場合は、querySelectorAll()メソッドを使用することもできます。


const parent = document.querySelector('#parent');
const children = parent.querySelectorAll(':scope > *');

console.log(children.length); // 3

 この場合、querySelectorAll()メソッドには、:scope という擬似クラスを使用して、直接の子要素のみを取得しています。* は全ての要素を意味します。

パフォーマンスの問題

 childNodesは、すべての子ノードを含むため、DOMツリーが大きい場合は、パフォーマンスの問題が生じる可能性があります。子要素が多い要素の childNodesプロパティにアクセスする場合、ブラウザは子要素をすべて走査する必要があります。したがって、childNodesを使用する前に、コードを最適化し、可能な限り効率的にすることが重要です。