JavaScriptの技法:DOM操作の落とし穴とその回避方法
翻訳校正:原井彰弘
JavaScriptでDOMを操作するのはAjaxアプリケーションでよく使われる。しかし、JavaScriptによるDOM探索は手間がかかり、落とし穴もある。ここではその回避方法を探ってみよう。
JavaScriptは、ウェブアプリケーションの開発で現在もっとも使用されている非常に便利なツールだ。しかし、JavaScriptはブラウザ内でリアルタイムに解釈されて動作するため、Document Object Model(DOM)を扱う際には細心の注意が必要となる。
DOMは、ウェブページを記録するためにブラウザで用いられているデータ構造だ。DOMはタグで構成されるツリー構造をしており、それぞれのタグにはHTML(またはXML)ドキュメントの形式に対応した複数のタグが子ノードとして含まれている。これらの内容は、JavaScriptを利用すればページが読み込まれた後でも動的に調べて変更することが可能であり、これがAJAXの大きな基盤となっている。
しかしながら、JavaScriptを用いてDOMの内部を探索するのは手間のかかる作業である。なぜなら、JavaScriptが保持しているすべての参照は動的であり、作業中に内容が変更される可能性もあるからだ。そのため、思いつきのアルゴリズムは多くの場合正しく動作しない。もし、スコープを変更したときに余分なメモリを割り当てて、変数をキャッシュするようなプログラミング言語を使用しており、その振る舞いに慣れてしまっているなら、なおさらそうである。
短い例を用いてこの問題を分かりやすく説明しよう。ここではJavaScriptを用い、DOMツリーを表現したテキストでページの内容を置換する関数を記述する。さて、ページの内部がどうなるのかを見て欲しい。例としては、以下のようなページを用いる。
<html> <head><title>Test Title</title></head> <body> <p>Test Text</p> <p><a href="http://builderau.com.au/">BuilderAU</a></p> </body> </html>
まず、ファイルの先頭に<script>要素を追加することから始めよう。この要素にはDOMの内容を出力するはずのprintDOM関数が含まれている。以下のようにしてbodyタグにコードを追加し、読み込み時にdocumentに対してprintDOM関数を実行するよう設定する。
<body onload="printDOM(document)">
続いてprintDOM関数を実装するのだが、まず以下のような実装を試みよう。
function printDOM(x) {
document.write(x)
for (var i = 0; i < x.children.length; i++) {
printDOM(x.children[i]);
}
}
ところで、このコードは以下のような出力を行う。
[object HTMLDocument][object HTMLHtmlElement][object HTMLHeadElement][object HTMLBodyElement][object Text]
一見このコードは正しく動作しているように見える。しかし、ドキュメントのもっとも重要な部分を忘れてはいけない。<p>タグとリンクがまったく含まれていないのだ。この原因は単純である。DOMをたどると同時にDOMに出力を行っているので、そのときに内容が変更されるのである。従って、HTMLの要素の子ノードを調べようとするときには、そのノードはすでに変更されて出力中のデータになっているのだ。ここでの教訓は、ドキュメントへの出力とドキュメントの過去の内容を調べる行為は、同時に行ってはいけないということである。
- 0人の推薦記事
- 2人がクリップ
-
ソーシャルブックマーク(-)
- トラックバック(0)
- 今日のトップ記事
- 昨日
- 3日前
- 4日前
- 5日前
- 7日前
- ホワイトペーパー
- 話題のタグ
仮想化Java環境のスループットを2倍に--BEA LiquidVMの適応型メモリ管理
Firefox 3が対応したdisplayプロパティの値(3) - inline-table
MSもアドビも学生さんに開発ソフトを無償提供
「Economist」のトップページがリニューアル
あなたがプログラムを理解できない10の理由:第2回
新APIまもなく登場--Google Developer Day 2008の見所とは?
内部統制対策を実現するIT運用管理ツール
-Simplify IT- ITをシンプルに 連載第2回
リスティング広告における競争優位性の維持