web-dev-qa-db-ja.com

JavaScriptで要素IDを識別子として使用しないのはなぜですか?

私が使用するようになったすべてのブラウザは、id="myDiv"を書くだけで:

myDiv

ここを参照してください: http://jsfiddle.net/L91q54Lt/

とにかく、この方法はかなり不十分に文書化されているようであり、実際、私が遭遇したソースはそれについて言及することさえせず、代わりに、

document.getElementById("myDiv")

または多分

document.querySelector("#myDiv")

そのIDが事前にわかっている(つまり、実行時に計算されていない)場合でも、DOM要素にアクセスする。後者のアプローチには、誰かが誤ってmyDivをより広いスコープで再定義しようとした場合(ただし、このような素晴らしいアイデアではありません...)、コードをいくつかの異なる値で上書きした場合にコードを安全に保つ利点があることがわかります。衝突に気づかずに続行します。

しかし、それ以外のことは?上記の短い形式をコードデザイン以外に使用することに懸念はありますか、それともここで何が不足していますか?

52
GOTO 0

とにかく、この方法はかなり不十分に文書化されているようであり、実際、私が遭遇したソースはそれに言及すらしていません[...]

暗黙的に宣言されたグローバル変数への依存はさておき、ドキュメントがないことは、それを使用しない大きな理由です。

id値のグローバル変数への明らかな昇格は標準に準拠しておらず( ID属性のHTML5仕様 は言及していない)、したがって、将来を想定するべきではありません。ブラウザはそれを実装します。

編集:この動作が判明 is 標準に準拠-HTML5では、windowは「名前付き要素」へのプロパティアクセスをサポートする必要があります:

上記のアルゴリズムの目的で、名前nameを持つ名前付きオブジェクトは、次のいずれかです。

  • 名前が name であるアクティブドキュメントの子ブラウジングコンテキスト
  • a、アプレット、エリア、埋め込み、フォーム、フレームセット、img、またはオブジェクトの要素で、値が name の名前コンテンツ属性を持つ、または
  • id コンテンツ属性がname.のコンテンツ属性を持つHTML要素

出典: HTML 5仕様、「ウィンドウオブジェクトへの名前付きアクセス」強調mine

これに基づいて、標準への準拠がこのパターンを回避する理由にはなりません。ただし、仕様自体はその使用を推奨していません。

原則として、これに依存するとコードが脆弱になります。最終的にこのAPIにマッピングされるIDは、時間の経過とともに変化する可能性があります。たとえば、Webプラットフォームに新機能が追加されているためです。これの代わりに、document.getElementById()またはdocument.querySelector()を使用します。

42
joews

すばらしい質問です。アインシュタインはおそらく言わなかったように、物事は可能な限り単純でなければならず、単純ではないはずです。

後者のアプローチには、誰かが誤ってより広い範囲でmyDivを再定義しようとした場合(ただし、このような素晴らしいアイデアではありません...)、コードを安全に保つ利点があり、それをいくつかの異なる値で上書きし、衝突に気付かずに続行します

これが悪い考えである主な理由であり、それで十分です。グローバル変数は信頼しても安全ではありません。それらは、ページで実行されるスクリプトによっていつでも上書きできます。

さらに、myDivと入力するだけではdocument.getElementById()の「短縮形」ではありません。これはグローバル変数への参照です。存在しないグローバル変数にアクセスしようとすると参照エラーがスローされるため、要素が存在しない場合はdocument.getElementById()が喜んでnullを返します。安全のために、try/catchブロックでグローバルへの参照をラップする必要があります。

これがjQueryが非常に人気がある理由の1つです。$("#myDiv").remove()を実行し、myDivのIDを持つ要素がない場合、エラーはスローされません。コードは黙って何もしません、これは多くの場合、DOM操作を行うときに正確に必要なものです。

20
Paul D. Waite

いくつかの理由があります。

コードとマークアップを結合したくない場合

特定の呼び出しを使用してdivにアクセスすることにより、グローバルスペースが破損することを心配する必要がありません。グローバルスペースでmyDivを宣言するライブラリを追加すると、修正するのが難しい苦痛の世界にいます。

DOMの一部ではない要素にIDでアクセスできます

それらは、切り離され、まだDOMに再接続されていないフラグメント、フレーム、または要素に含めることができます。

編集:ID)によって非接続要素にアクセスする例

var frag = document.createDocumentFragment();
var span = document.createElement("span");
span.id = "span-test";
frag.appendChild(span);
var span2 = frag.getElementById("span-test");
alert(span === span2);
12

私の場合、ページ内にiframeがありました。 id属性とname属性のどちらが原因で混乱していたのか、どちらもwindowからアクセスできるinner_iframeという変数に影響を与えていました。

  • id属性のみを使用した場合、id="inner_iframe"のように、window.inner_iframeHTMLIFrameElementになります。プロパティには inner_iframe.contentDocument およびinner_iframe.contentWindowここで説明 *が含まれます

  • name属性のみを使用した場合、name="inner_iframe"のように、window.inner_iframeは「フレーム」、つまり 「ウィンドウオブジェクト」contentWindow、したがって、名前属性inner_iframeはnotにプロパティcontentDocumentまたはcontentWindowがあります。

  • bothnameidの両方の属性を使用し、両方の属性に同じ値を指定した場合name="inner_iframe" id="inner-iframe"; name属性は、id属性を踏みにじったり覆ったりしました。 「ウィンドウオブジェクト」notHTMLIFrameElementが残りました!

したがって、私のポイントはあいまいさについて注意することです。 2つの異なるAPIを持つ同じオブジェクトのname属性とid属性の競合:暗黙的な動作とウィンドウ変数へのアタッチが混乱する特定のケースにすぎません。

*(および<script>がHTMLの<iframe>の後ろ/下にロードされた場合、または<script>window.onloadまで待機してからid属性でアクセスしようとした場合のみ)

**この「フレーム」とDOM要素の違いは、Mozillaのドキュメントでは次のように説明されています。

Window.frames疑似配列の各項目は、指定されたのコンテンツに対応するウィンドウオブジェクトを表します(i)フレームのDOM要素ではありません(つまり、window.frames [0]はdocument.getElementsByTagName( "iframe")[0] .contentWindowと同じです)。

2
The Red Pea