子ノードを取得する最良の方法


233

JavaScriptには、任意の要素から最初の子要素を取得するためのさまざまなメソッドが用意されていますが、どれが最適ですか。つまり、動作に関しては、ブラウザ間の互換性が最も高く、高速で、包括的で、予測可能です。エイリアスとして使用するメソッド/プロパティのリスト:

var elem = document.getElementById('container');
var child = elem.children[0];
var child = elem.firstElementChild; // == children[0]

これはどちらの場合でも機能します。

var child = elem.childNodes[0]; // or childNodes[1], see below

これは、フォームまたは<div>反復の場合です。テキスト要素に遭遇する可能性がある場合:

var child = elem.childNodes; // treat as NodeList
var child = elem.firstChild;

私ができる限り、firstChildからのNodeList childNodesfirstElementChild使用し、を使用しchildrenます。私はこの仮定をMDNリファレンスに基づいています。

childNode要素ノードの最初の子要素への参照、またはnull存在しない場合。

速度の点では、firstElementChildは事実上への参照children[0]であり、childrenオブジェクトはすでにメモリ内に既に存在するため、違いがあってもほとんどありません。

私を投げるのはchildNodesオブジェクトです。これを使用して、テーブル要素のフォームを確認しました。childrenはすべてのフォーム要素をリストchildNodesしていますが、HTMLコードの空白も含まれているようです。

console.log(elem.childNodes[0]);
console.log(elem.firstChild);

両方のログ <TextNode textContent="\n ">

console.log(elem.childNodes[1]);
console.log(elem.children[0]);
console.log(elem.firstElementChild);

すべてのログ<input type="text">。どうして?1つのオブジェクトで「生の」HTMLコードを操作できるようにする一方で、他のオブジェクトはDOMに固執することを理解していますが、childNodes要素は両方のレベルで機能するようです。

私の最初の質問に戻るために、私の推測は次のようになります:最も包括的なオブジェクトが必要な場合、それchildNodesが方法ですが、その包括性のため、必要な要素を返すという点で最も予測しにくいかもしれません/いつでも期待しています。その場合、ブラウザー間のサポートも課題となる可能性がありますが、私は間違っている可能性があります。

誰かが手元にあるオブジェクトの違いを明確にできますか?速度差があっても無視できる程度であれば、私も知りたい。これがすべて間違っていると思われる場合は、遠慮なく教えてください。


PS:ええと、どうか、私はJavaScriptが好きなので、そうです、この種のことを扱いたいのです。「jQueryがこれを処理します」のような答えは私が探しているものではないため、いいえ 鬼ごっこ。


50
>>お願いします、お願いします。JavaScriptが好きなので、そういうことを扱いたいと思います。「jQueryがこれを処理します」のような答えは、私が探しているものではありません<<賛成投票
david.barkhuizen

回答:


211

考えすぎているようですね。childNodesとの違いを確認しました。childrenつまりchildNodes、完全に空白で構成されるテキストノードを含むすべてのノードを含みchildren、は要素である子ノードのみのコレクションです。これですべてです。

注意すべき問題がいくつかありますが、どちらのコレクションについても予測できないことはありません。

  • IE <= 8には、空白のみのテキストノードは含まれませんが、childNodes他のブラウザには含まれます
  • IE <= 8にはコメントノードが含まれますがchildren、他のブラウザには要素しかありません

childrenfirstElementChildそして友達は便利なだけで、要素だけに制限されたDOMのフィルターされたビューを表示します。


同じように考えましたが、まだ1つ問題があります。childNodesが取得する空白のtextnodeは、実際にはコードの新しい行といくつかのタブです。これはXHTML Doctypeによるものですか?タグ内のstructコードに空白を含めることでこれを解決できますか?
エリアスヴァンOotegem

@EliasVanOotegem:それはdoctypeとは無関係です。空白のテキストノードは、HTMLとXHTMLの両方で、ソースのどこに出現しても、常にDOMに含まれます(IE <9を除く)。準備ができていないと気付く可能性はありますが、一般的には良いことです。
Tim Down

このように私のマークアップを書くのに役立つかどうかを意味しました<td\n\t>content</td>。XMLの場合と同様に、余計な空白がデータ(この場合はDOM)の一部と見なされないようにします。タグ内の空白がDOMに含まれるのはなぜですか?
エリアスヴァンOotegem

@EliasVanOotegem:ああ、なるほど。タグ内のタグ名の後の空白は無視されるので、そのようなことを行うことができます。私は、ブラウザが特定の種類の要素の間に空白のための小さなギャップを追加するのを防ぐために、正確なレイアウトで使用される手法を見てきました。
Tim Down

2
@Christophe:ああ、公平な点、ありがとう。回答にメモを追加します。これchildrenは、IEが10年以上前に標準になり、他のブラウザで採用される前に始まったので、IE <= 8が正しく、他のブラウザが間違っていると主張できます。
Tim Down

23

firstElementChildはIE <9では使用できない場合があります(firstChildのみ)

MS DOM(IE <9)は空のテキストノードを格納していないため、IE <9ではfirstChildがfirstElementChildです。しかし、他のブラウザでそうすると、空のテキストノードが返されます...

私の解決策

child=(elem.firstElementChild||elem.firstChild)

これはIE <9でも最初の子供を与えるでしょう


elem.firstChildが要素ノードではない場合、elem.firstElementChildは常に要素ノードであるため、結果は古いIEでは異なります。
duri

すみませんが、すべての主要ブラウザで最初の子を取得する方法を知っています。私が知りたいのは、オブジェクトの類似点と相違点をよりよく理解するために、さまざまなオブジェクトがどのように構造化されているかです。後で質問を編集して、わかりやすくするために混乱を
招きます

1
firstElementChildIE以外のブラウザでも必ずしも安全ではありません。Firefoxはバージョン3.5でのみサポートを開始しました。
Tim Down、

これは、chrome、IE9、IE8で機能します。これは、firstElementChildがある場合、他のチェックが実行されないためです。それ以外の場合(古いIE)には、firstChildがあり、firstElementChildがないブラウザの要素ノードです(IE <9 )... FFについてはまだ疑問に思う
neu-rah

1
Timは正解です。これらのオブジェクトについて
何か

20

クロスブラウザーの方法は、を使用childNodesして取得しNodeListnodeType ELEMENT_NODEを使用してすべてのノードの配列を作成することです。

/**
 * Return direct children elements.
 *
 * @param {HTMLElement}
 * @return {Array}
 */
function elementChildren (element) {
    var childNodes = element.childNodes,
        children = [],
        i = childNodes.length;

    while (i--) {
        if (childNodes[i].nodeType == 1) {
            children.unshift(childNodes[i]);
        }
    }

    return children;
}

http://jsfiddle.net/s4kxnahu/

lodashなどのユーティリティライブラリを使用している場合、これは特に簡単です。

/**
 * Return direct children elements.
 *
 * @param {HTMLElement}
 * @return {Array}
 */
function elementChildren (element) {
    return _.where(element.childNodes, {nodeType: 1});
}

未来:

疑似クラスquerySelectorAllと組み合わせて使用できます:scope(セレクターの参照ポイントである要素に一致します)。

parentElement.querySelectorAll(':scope > *');

執筆時点では、これ:scope Chrome、Firefox、Safariでサポートされています。


:scopeが仕様から削除されました未来セクションを削除する必要がありますか?
Thomas Marti

4

他の答えを追加するために、特に<svg>要素を処理する場合は、ここでも注目すべき違いがあります。

私はとの両方.childNodesを使用しており、ゲッターによって配信されたものを使用する.childrenことを推奨しています。HTMLCollection.children

しかし今日、でを使用.childrenするとIE / Edgeが失敗するという問題に遭遇しました<svg>。一方で.children、基本的なHTML要素にIEでサポートされ、それが文書/文書の断片、でサポートされていないか、 SVG要素

私にとっては、気にする必要の.childNodes[n]ない余分なテキストノードがないため、必要な要素を経由して簡単に取得できました。同じことができるかもしれませんが、上記の他の場所で述べたように、予期しない要素に遭遇する可能性があることを忘れないでください。

これが.children、最新のIEでjsの他の場所で機能し、ドキュメントまたはSVG要素で失敗する理由を理解しようとする頭をひっくり返す人に役立つことを願っています。


3

みなさん、ホワイトスペースに騙されてはいけません。これをコンソールブラウザでテストしてください。ネイティブJavaScriptを使用します。以下は、同じクラスの2つの「ul」セットの例です。空白を避けるために 'ul'リストをすべて1行にする必要はありません。配列カウントを使用して空白を飛び越えてください。

どのように周りの白いスペースを取得するためにquerySelector()、その後childNodes[]フィドルリンクをJS:https://jsfiddle.net/aparadise/56njekdo/

var y = document.querySelector('.list');
var myNode = y.childNodes[11].style.backgroundColor='red';

<ul class="list">
    <li>8</li>
    <li>9</li>
    <li>100</li>
</ul>

<ul class="list">
    <li>ABC</li>
    <li>DEF</li>
    <li>XYZ</li>
</ul>

私の反対票ではありませんが、誰かが反対票を投じたのは、次の理由からだと思いますdocument.querySelector。b)の質問は基本的に違いが間にあるものを求めているchildrenchildNodes 、内部で他の上で1つを選択する際に、より信頼性のあります、。およびc)質問でchildNodes children
デモントレード
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.