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に対して、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>
この結果、開発ツールのログには、以下のように出力されます。
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>
ログには次のように表示されました。
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>
上記の部分の 「
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>
ログには次のように表示されました。
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を設置しました。
<!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>
今度は、出力結果は次のようになります。
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の状態に応じて注意して実装する必要がありそうです。