firstChild / lastChild / firstElementChild / lastElementChild

子要素の最初や最後を取得するプロパティがいくつかあります。firstChild / lastChildfirstElementChild / lastElementChild の違いを理解しましょう。

4つのプロパティ

プロパティ取得対象
firstChild最初の子ノード(テキスト含む)
lastChild最後の子ノード(テキスト含む)
firstElementChild最初の子要素(Element のみ)
lastElementChild最後の子要素(Element のみ)

違いの例

<ul id="list">
  <li>項目1</li>
  <li>項目2</li>
  <li>項目3</li>
</ul>
const list = document.getElementById('list');

// firstChild は改行のテキストノード
console.log(list.firstChild);        // #text
console.log(list.firstChild.nodeType); // 3(Text)

// firstElementChild は最初の li 要素
console.log(list.firstElementChild);        // <li>項目1</li>
console.log(list.firstElementChild.nodeType); // 1(Element)

実際に動かしてみよう

HTML
CSS
JavaScript
<ul id="list">
  <li>最初の項目</li>
  <li>真ん中の項目</li>
  <li>最後の項目</li>
</ul>
<button id="firstBtn">最初を強調</button>
<button id="lastBtn">最後を強調</button>
#list li { padding: 8px; }
.highlight { background: #ffeb3b; }
const list = document.getElementById('list');

document.getElementById('firstBtn').addEventListener('click', () => {
  list.querySelectorAll('li').forEach(li => li.classList.remove('highlight'));
  list.firstElementChild.classList.add('highlight');
});

document.getElementById('lastBtn').addEventListener('click', () => {
  list.querySelectorAll('li').forEach(li => li.classList.remove('highlight'));
  list.lastElementChild.classList.add('highlight');
});

子要素がない場合

子要素が存在しない場合は null を返します。

const empty = document.getElementById('empty-div');
console.log(empty.firstElementChild); // null

childNodes / children との関係

const list = document.getElementById('list');

// 同じ結果
list.firstElementChild === list.children[0]                    // true
list.lastElementChild === list.children[list.children.length - 1] // true

// childNodes でも取れるが面倒
list.childNodes[0] // テキストノードかもしれない

どれを使うべきか

Element を取得したい場合がほとんどなので、firstElementChild / lastElementChild を使いましょう。

firstChild / lastChild

テキストノードも含む。特別な理由がなければ使わない

firstElementChild / lastElementChild

Element だけを返す。通常はこちらを使う

テキストノードを操作したい特殊なケース以外は、firstElementChild / lastElementChild で十分です。