uhyohyo.net

JavaScript初級者から中級者になろう

二章第四回 木構造の操作:ノードの除去

このページの最終更新日:

今回は、木構造からノードをまるまる除去してしまう方法を解説します。

removeChild

それには、removeChildというメソッドを使います。これは、ノードが持つメソッドです。

まず使用例を見てみましょう。サンプルには、前回と同様のものを使います。

<!doctype html>
<html>
  <head>
    <title>test</title>
  </head>
  <body>
    <p id="aaaaa">t<strong>es</strong>t</p>

    <script type="text/javascript">
      var p = document.getElementById('aaaaa');
      var children = p.childNodes;
      var textnode = children[0];	//テキストノード
      p.removeChild(textnode);
    </script>
  </body>
</html>

実行すると、画面には「est」と表示されています。最初の「t」が消えてしまいました。

これは、実はこういうことです。

p
  • #text "t"
  • strong
    • #text "es"
  • #text "t"

↓↓↓

p
  • strong
    • #text "es"
  • #text "t"

最初のテキストノードが消えてしまいました。

removeChildは、「自身の子ノードのうち、引数のノードが表すノードを除去する」というメソッドです。

上のサンプルで、引数はtextnodeで、textnodeはpの子ノードの0番目のノードでした。つまり、引数のノードが表すノードとは、pの0番目の子ノードということになりますね。従って、それが除去されたというわけです。

ちなみに、除去されたノードは木構造から取り除かれただけであり、即座に消滅したわけではありません。これはどういうことかというと、除去したノードは、また別の場所で使ったりできるということです。これは、また別の機会に解説します。

さて、innerHTMLでやったような書き換えを実現するには、strong要素がまだ余計です。同様にしてこれも除去してしまいましょう。

var p = document.getElementById('aaaaa');
var children = p.childNodes;
var textnode = children[0];	//テキストノード
p.removeChild(textnode);
var strong = children[0];  //strong要素
p.removeChild(strong);

ここで注意すべき点は、strong要素を取得するのに再びchildren[0]としていることです。最初の木構造ではstrong要素はpの1番目の子でしたが、削除後はpの0番目の子に変化しています。

実際、次のように、ノードを除去する前にstrong要素を取得するならば、1番目となります。

var p = document.getElementById('aaaaa');
var children = p.childNodes;
var textnode = children[0];	//テキストノード
var strong = children[1];  //strong要素
p.removeChild(textnode);
p.removeChild(strong);

ちなみに、さらに子を持つ要素を除去すると(今回の場合strongがさらに#textを子に持っていますね)、その子ごとまとめてなくなります。よって、strong要素を除去したあとの木構造は次のようになります。

p
  • #text "t"

このようになります。

だから、上のサンプルを実行すると「t」だけ残りました。このとき、この#textはまた0番目です。そこで、

var p = document.getElementById('aaaaa');
var children = p.childNodes;
var textnode = children[0];	//テキストノード
p.removeChild(textnode);
var strong = children[0]
p.removeChild(strong);

children[0].nodeValue = "書き換えました";

のようにしてこれを書き換えれば、

p
  • #text "書き換えました"

となって、見事p要素の中身は「書き換えました」だけになるわけです。

子ノードの全除去

今回の場合、p要素の中身を#textひとつだけ残しましたが、要素の子ノードを全部なくしたいということもよくあります。基本的には今回のremoveChildを使って1つずつ除去することになります。(第八章で紹介する方法を使って全部まとめて除去する方法も一応あります。)

練習問題のような感じになりますが、これをやってみましょう。

まず、子ノードが何個あるか分からないから繰り返しの文を使うということは分かります。今回はwhile文を使います。


<!doctype html>
<html>
  <head>
    <title>test</title>
  </head>
  <body>
    <p>これは1つ目の段落です。</p>
    <p id="aaaaa">t<strong>es</strong>t</p>
    <p>これは3つ目の段落です。</p>

    <script type="text/javascript">
      var p = document.getElementById('aaaaa');
      var children = p.childNodes;

      while( p.hasChildNodes() ){
        p.removeChild( children.item(0) );
      }
    </script>
  </body>
</html>

ページを開くと、「これは1つ目の段落です。」と「これは3つ目の段落です。」の間には何も表示されません。これは、真ん中のp要素の中身が全部消えたことを示しています。

まず、一つ新しいメソッドが出ています。hasChildNodesです。これはノードが持つメソッドです。引数はありません。

このメソッドは簡単で、そのノードが子ノードを持っていればtrueを返し、持っていなければfalseを返します

つまり、このwhileは、p要素が子ノードを持っている限り繰り返し続けるというわけです。

さて、繰り返される処理は1文だけです。childrenはp要素の子ノードのNodeListなので、removeChildでp要素の0番目(最初)の要素を除去しているというわけです。

実は、NodeListは木構造の変化を常に反映します。よって、pが子ノードを持っている限り「0番目の子ノード」は存在します。最後の子ノードをremoveChildで除去した後、hasChildNodesはfalseを返すため、そこでwhileが終了します。

firstChild

実は、ノードはfirstChildというプロパティを持っています。意味は「最初の子」、つまり「0番目の子ノード」です。だから、当然代入されているのはノードです。書き換えはできません。これを使えば、childNodesを通さずに直接0番目の子を取得できます。つまり、上のサンプルはこう書き換えられます。

while( p.hasChildNodes() ){
    p.removeChild( children.item(0) );
}

↓↓↓

while( p.hasChildNodes() ){
    p.removeChild(p.firstChild);
}

また、余談ですが、p.hasChildNodes()は、p.childNodes.length!=0としても同じ事ができます。

ついでに紹介すると、lastChildというプロパティもあります。これは「一番最後の子」です。