firstChild、lastChildによる探索

javascript

firstChild、lastChildによる探索

親要素からみて子要素をfirstChildとlastChildで取得する方法を試してみます。
まずは、前回投稿したHTMLを少し改造して、下記のHTMLを用意しました。

<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>テストHTML</title>
</head>
<body>

<div id="test1">
	<div id="p1">p1text</div>
	<div id="p2">p2text
		<div id="c1">c1text</div>
		<div id="c2">c2text</div>
		<div id="c3">c3text</div>
		<div id="c4">c4text</div>
	</div>
	<div id="p3">p3text
		<div id="d1">d1text</div>
		<div id="d2">d2text</div>
		<div id="d3">d3text</div>
		<div id="d4">d4text</div>
	</div>
</div>
</div>

</body>
</html>

サーバ上のHTMLはこちら(test1)

このHTMLに対して、idがp2のdivタグを親として、子要素をfirstChildを使って取得してみます。
下記のようにjavascriptを追記しました。

<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>テストHTML</title>
</head>
<body>

<div id="test1">
	<div id="p1">p1text</div>
	<div id="p2">p2text
		<div id="c1">c1text</div>
		<div id="c2">c2text</div>
		<div id="c3">c3text</div>
		<div id="c4">c4text</div>
	</div>
	<div id="p3">p3text
		<div id="d1">d1text</div>
		<div id="d2">d2text</div>
		<div id="d3">d3text</div>
		<div id="d4">d4text</div>
	</div>
</div>

<script type="text/javascript">
	let p2 = document.getElementById("p2");
	console.log("p2.firstChild -> " + p2.firstChild);
</script>

</body>
</html>

サーバ上のHTMLはこちら(test2)

この結果、開発ツールのログには、以下のように出力されます。

p2.firstChild -> [object Text]

親要素のp2に対して、オブジェクトの「Text」が取得できていることがわかります。
次に、この p2.firstChild の内容を詳しく出力してみます。
愚直な方法ですが、for 取得できたp2.firstChildの内容を全てみてみます。

先ほどのHTMLに追記して、下記のように変更しました。

<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>テストHTML</title>
</head>
<body>

<div id="test1">
	<div id="p1">p1text</div>
	<div id="p2">p2text
		<div id="c1">c1text</div>
		<div id="c2">c2text</div>
		<div id="c3">c3text</div>
		<div id="c4">c4text</div>
	</div>
	<div id="p3">p3text
		<div id="d1">d1text</div>
		<div id="d2">d2text</div>
		<div id="d3">d3text</div>
		<div id="d4">d4text</div>
	</div>
</div>

<script type="text/javascript">
	let p2 = document.getElementById("p2");
	console.log("p2.firstChild -> " + p2.firstChild);

	// 「p2.firstChild」の内容を確認する
	for(var key in p2.firstChild){
		console.log(key + " : " + p2.firstChild[key]);
	}
</script>

</body>
</html>

サーバ上のHTMLはこちら(test3)

ログには次のように表示されました。

p2.firstChild -> [object Text]
wholeText : p2text
		
assignedSlot : null
splitText : function splitText() { [native code] }
data : p2text
		
length : 9
previousElementSibling : null
nextElementSibling : [object HTMLDivElement]
after : function after() { [native code] }
appendData : function appendData() { [native code] }
before : function before() { [native code] }
deleteData : function deleteData() { [native code] }
insertData : function insertData() { [native code] }
remove : function remove() { [native code] }
replaceData : function replaceData() { [native code] }
replaceWith : function replaceWith() { [native code] }
substringData : function substringData() { [native code] }
nodeType : 3
nodeName : #text
baseURI : https://propansystem.net/blogsample/js/025/test3.html
isConnected : true
ownerDocument : [object HTMLDocument]
parentNode : [object HTMLDivElement]
parentElement : [object HTMLDivElement]
childNodes : [object NodeList]
firstChild : null
lastChild : null
previousSibling : null
nextSibling : [object HTMLDivElement]
nodeValue : p2text
		
textContent : p2text
		
ELEMENT_NODE : 1
ATTRIBUTE_NODE : 2
TEXT_NODE : 3
CDATA_SECTION_NODE : 4
ENTITY_REFERENCE_NODE : 5
ENTITY_NODE : 6
PROCESSING_INSTRUCTION_NODE : 7
COMMENT_NODE : 8
DOCUMENT_NODE : 9
DOCUMENT_TYPE_NODE : 10
DOCUMENT_FRAGMENT_NODE : 11
NOTATION_NODE : 12
DOCUMENT_POSITION_DISCONNECTED : 1
DOCUMENT_POSITION_PRECEDING : 2
DOCUMENT_POSITION_FOLLOWING : 4
DOCUMENT_POSITION_CONTAINS : 8
DOCUMENT_POSITION_CONTAINED_BY : 16
DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC : 32
appendChild : function appendChild() { [native code] }
cloneNode : function cloneNode() { [native code] }
compareDocumentPosition : function compareDocumentPosition() { [native code] }
contains : function contains() { [native code] }
getRootNode : function getRootNode() { [native code] }
hasChildNodes : function hasChildNodes() { [native code] }
insertBefore : function insertBefore() { [native code] }
isDefaultNamespace : function isDefaultNamespace() { [native code] }
isEqualNode : function isEqualNode() { [native code] }
isSameNode : function isSameNode() { [native code] }
lookupNamespaceURI : function lookupNamespaceURI() { [native code] }
lookupPrefix : function lookupPrefix() { [native code] }
normalize : function normalize() { [native code] }
removeChild : function removeChild() { [native code] }
replaceChild : function replaceChild() { [native code] }
addEventListener : function addEventListener() { [native code] }
dispatchEvent : function dispatchEvent() { [native code] }
removeEventListener : function removeEventListener() { [native code] }

p2.firstChildの要素にアクセスし、テキストオブジェクトの内容が列挙されて出力されました。
出力内容の中の「data」プロパティをみると、「data : p2text」と表示されていることから、

	<div id="p2">p2text
		<div id="c1">c1text</div>
		<div id="c2">c2text</div>
		<div id="c3">c3text</div>
		<div id="c4">c4text</div>
	</div>

上記の部分の 「

p2text 」の要素が取得されていることがわかります。
id 「p2」に対しての一番最初の要素としてp2textという文字列(テキストオブジェクトのdata)が出力されています。

では次に「lastChild」の場合はどうなるか、試してみます。
1つ前のHTMLを以下のように書き換えて画面にアクセスしてみます。

<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>テストHTML</title>
</head>
<body>

<div id="test1">
	<div id="p1">p1text</div>
	<div id="p2">p2text
		<div id="c1">c1text</div>
		<div id="c2">c2text</div>
		<div id="c3">c3text</div>
		<div id="c4">c4text</div>
	</div>
	<div id="p3">p3text
		<div id="d1">d1text</div>
		<div id="d2">d2text</div>
		<div id="d3">d3text</div>
		<div id="d4">d4text</div>
	</div>
</div>

<script type="text/javascript">
	let p2 = document.getElementById("p2");
	console.log("p2.lastChild -> " + p2.lastChild);

	// 「p2.lastChild」の内容を確認する
	for(var key in p2.lastChild){
		console.log(key + " : " + p2.lastChild[key]);
	}
</script>

</body>
</html>

サーバ上のHTMLはこちら(test4)

ログには次のように表示されました。

p2.lastChild -> [object Text]
wholeText : 
	
assignedSlot : null
splitText : function splitText() { [native code] }
data : 
	
length : 2
previousElementSibling : [object HTMLDivElement]
nextElementSibling : null
after : function after() { [native code] }
appendData : function appendData() { [native code] }
before : function before() { [native code] }
deleteData : function deleteData() { [native code] }
insertData : function insertData() { [native code] }
remove : function remove() { [native code] }
replaceData : function replaceData() { [native code] }
replaceWith : function replaceWith() { [native code] }
substringData : function substringData() { [native code] }
nodeType : 3
nodeName : #text
baseURI : https://propansystem.net/blogsample/js/025/test4.html
isConnected : true
ownerDocument : [object HTMLDocument]
parentNode : [object HTMLDivElement]
parentElement : [object HTMLDivElement]
childNodes : [object NodeList]
firstChild : null
lastChild : null
previousSibling : [object HTMLDivElement]
nextSibling : null
nodeValue : 
	
textContent : 
	
ELEMENT_NODE : 1
ATTRIBUTE_NODE : 2
TEXT_NODE : 3
CDATA_SECTION_NODE : 4
ENTITY_REFERENCE_NODE : 5
ENTITY_NODE : 6
PROCESSING_INSTRUCTION_NODE : 7
COMMENT_NODE : 8
DOCUMENT_NODE : 9
DOCUMENT_TYPE_NODE : 10
DOCUMENT_FRAGMENT_NODE : 11
NOTATION_NODE : 12
DOCUMENT_POSITION_DISCONNECTED : 1
DOCUMENT_POSITION_PRECEDING : 2
DOCUMENT_POSITION_FOLLOWING : 4
DOCUMENT_POSITION_CONTAINS : 8
DOCUMENT_POSITION_CONTAINED_BY : 16
DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC : 32
appendChild : function appendChild() { [native code] }
cloneNode : function cloneNode() { [native code] }
compareDocumentPosition : function compareDocumentPosition() { [native code] }
contains : function contains() { [native code] }
getRootNode : function getRootNode() { [native code] }
hasChildNodes : function hasChildNodes() { [native code] }
insertBefore : function insertBefore() { [native code] }
isDefaultNamespace : function isDefaultNamespace() { [native code] }
isEqualNode : function isEqualNode() { [native code] }
isSameNode : function isSameNode() { [native code] }
lookupNamespaceURI : function lookupNamespaceURI() { [native code] }
lookupPrefix : function lookupPrefix() { [native code] }
normalize : function normalize() { [native code] }
removeChild : function removeChild() { [native code] }
replaceChild : function replaceChild() { [native code] }
addEventListener : function addEventListener() { [native code] }
dispatchEvent : function dispatchEvent() { [native code] }
removeEventListener : function removeEventListener() { [native code] }

p2.firstChildの取得の時と同様に、要素内の値を「data」のプロパティで取得できるかと思いましたが、
p2.lastChildの場合は、実際には何も取得はされず、空白(厳密にいうとソース内のタブ文字列)が出力されています。

では、p2.lastChildはどこの何を取得しようとしているのか、もう少し詳しく調べてみます。

先ほどのHTMLを変更して、次のHTMLを設置しました。

の要素の最後に「p2text2」という文字列を記述してみました。

<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>テストHTML</title>
</head>
<body>

<div id="test1">
	<div id="p1">p1text</div>
	<div id="p2">p2text
		<div id="c1">c1text</div>
		<div id="c2">c2text</div>
		<div id="c3">c3text</div>
		<div id="c4">c4text</div>
		p2text2
	</div>
	<div id="p3">p3text
		<div id="d1">d1text</div>
		<div id="d2">d2text</div>
		<div id="d3">d3text</div>
		<div id="d4">d4text</div>
	</div>
</div>

<script type="text/javascript">
	let p2 = document.getElementById("p2");
	console.log("p2.lastChild -> " + p2.lastChild);

	// 「p2.lastChild」の内容を確認する
	for(var key in p2.lastChild){
		console.log(key + " : " + p2.lastChild[key]);
	}
</script>

</body>
</html>

サーバ上のHTMLはこちら(test5)

今度は、出力結果は次のようになります。

p2.lastChild -> [object Text]
wholeText : 
		p2text2
	
assignedSlot : null
splitText : function splitText() { [native code] }
data : 
		p2text2
	
length : 12
previousElementSibling : [object HTMLDivElement]
nextElementSibling : null
after : function after() { [native code] }
appendData : function appendData() { [native code] }
before : function before() { [native code] }
deleteData : function deleteData() { [native code] }
insertData : function insertData() { [native code] }
remove : function remove() { [native code] }
replaceData : function replaceData() { [native code] }
replaceWith : function replaceWith() { [native code] }
substringData : function substringData() { [native code] }
nodeType : 3
nodeName : #text
baseURI : https://propansystem.net/blogsample/js/025/test5.html
isConnected : true
ownerDocument : [object HTMLDocument]
parentNode : [object HTMLDivElement]
parentElement : [object HTMLDivElement]
childNodes : [object NodeList]
firstChild : null
lastChild : null
previousSibling : [object HTMLDivElement]
nextSibling : null
nodeValue : 
		p2text2
	
textContent : 
		p2text2
	
ELEMENT_NODE : 1
ATTRIBUTE_NODE : 2
TEXT_NODE : 3
CDATA_SECTION_NODE : 4
ENTITY_REFERENCE_NODE : 5
ENTITY_NODE : 6
PROCESSING_INSTRUCTION_NODE : 7
COMMENT_NODE : 8
DOCUMENT_NODE : 9
DOCUMENT_TYPE_NODE : 10
DOCUMENT_FRAGMENT_NODE : 11
NOTATION_NODE : 12
DOCUMENT_POSITION_DISCONNECTED : 1
DOCUMENT_POSITION_PRECEDING : 2
DOCUMENT_POSITION_FOLLOWING : 4
DOCUMENT_POSITION_CONTAINS : 8
DOCUMENT_POSITION_CONTAINED_BY : 16
DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC : 32
appendChild : function appendChild() { [native code] }
cloneNode : function cloneNode() { [native code] }
compareDocumentPosition : function compareDocumentPosition() { [native code] }
contains : function contains() { [native code] }
getRootNode : function getRootNode() { [native code] }
hasChildNodes : function hasChildNodes() { [native code] }
insertBefore : function insertBefore() { [native code] }
isDefaultNamespace : function isDefaultNamespace() { [native code] }
isEqualNode : function isEqualNode() { [native code] }
isSameNode : function isSameNode() { [native code] }
lookupNamespaceURI : function lookupNamespaceURI() { [native code] }
lookupPrefix : function lookupPrefix() { [native code] }
normalize : function normalize() { [native code] }
removeChild : function removeChild() { [native code] }
replaceChild : function replaceChild() { [native code] }
addEventListener : function addEventListener() { [native code] }
dispatchEvent : function dispatchEvent() { [native code] }
removeEventListener : function removeEventListener() { [native code] }

p2.lastChild のdataプロパティにある「p2text2」という文字列が出力されていることがわかります。

ただし、上記の例の場合、半ば強引に値を取得するようにHTMLを記述したので、
実際には厳密な仕様を把握していません。

仕様上は、p2のノードのうち、最後の子ノードを取得するのがlastChildで、子ノードがない場合はnullを取得する。という仕様になります。

このあたりは実際のコーディングやHTML側のDOMの状態に応じて注意して実装する必要がありそうです。

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です