Jintrick.netagenda2002年12月アーカイブ → 2002年12月05日

MS版DOM1 HTMLの落とし穴

この一年間、HTMLには悩まされ続けてきましたが、今回が一番嵌りました。次の糞HTMLの糞フラグメントをご覧下さい。

<p id="parent">
  <b id="me">
    <ul id="child">
      <li>list item</li>
    </ul>
  </b>
</p>

さて、この例のb要素(HTML B Element)へのポインタを幾つか作成したいと思います。親からアクセスするか、子からアクセスするかというニ通りの経路を考えます。

1.
var elmBviaParent = undefined;
var nlBSiblings = document.getElementById('parent').childNodes;
for(var i=0; i<nlBSiblings.length; i++)
{
  if(nlBSiblings.item(i).id == 'me')
  elmBviaParent = nlBSiblings.item(i);
}
2.
var elmBviaChild = document.getElementById('child').parentNode

この2つの変数が共に同一のb要素へのポインタになっている事を確かめる為、まずid属性値を比較してみます。

これは真です。共に「me」という文字列になっています。Internet Explorer6は、b要素の子としてul要素を持てるということでしょうか。

しかし、ここが怪しい部分です。そのまま比較してみましょう。

これも真です。まあ私は勝手に型変換されるのが恐いので、その必要がない限りは===で比較するようにしています。すると:

さあこれは偽です。falseです。両者がポイントしているのは違うオブジェクトであることが判明しました。==演算子で比較した場合は、型変換を通じて真だったのです。

両者の内のどちらかは、DOM1 HTMLのElement型では無いということでしょうか。これだからJScriptの==演算子は恐いのです。String型とNumber型以外ではどういう型変換が行われるのかはっきりしたことが分からないのです。特に恐いのは、効率の問題です。任意の2つのオブジェクトを比較した時、コード作成者には未知の数の型変換がトライされるのではないかと思うと、とてもじゃあないですが使う気になれません。因みにこれと似たような理由で、最近はwith文を使うのを止めました。

それはさておき、どちらが「なんちゃってElement型」なのかを確認する為、お馴染みの方法でもう一つのポインタを作成してみます。getElementByIdメソッドです。

3.
var elmB = document.getElementById('me')

1. 、2. 両者を、このelmBと比較してみます。

1-1.
elmBviaParent === elmB
2-1.
elmBviaChild === elmB

2-1. が偽です。b要素の子要素のul要素からparentNodeであるb要素を参照した場合には、Element型ではない何か未知の型「なんちゃってElement型」になっていると想像します。ではこの「なんちゃってElement型」は、DOM1 CoreのElementインターフェイスを実装しているのかといえば、しているようです。MS独自拡張のオマケの部分も含め、アトリビュートもメソッドも、全部実装しています。

IEならではの比較方法

そういうわけで、私はString、Number以外のオブジェクトを==演算子で比較したくないんです。何が行われているか良く分からないからです。では上の1. と 2. を比較して、型は兎も角同一の「要素」を参照しているかどうかを調べるにはどうすれば良いでしょうか。

Internet Explorerは、HTML文書の各要素にその登場順の番号を割り当てています。一意の識別子といえるでしょう。これはsourceIndexプロパティで参照できます。

elmBviaChild.sourceIndex === elmBviaParent.sourceIndex

そもそも

しかし、b要素の子にul要素を作るのはHTMLの文法違反であり、文法を守っていればこの問題は起りません。従って、責任はInternet Explorer側にはありません。


webmaster@jintrick.net
公開: 2002年12月05日
カテゴリ: DOM ,Javascript ,意見交換, 批判等