【问题标题】:Why don't we just use element IDs as identifiers in JavaScript?为什么我们不直接使用元素 ID 作为 JavaScript 中的标识符?
【发布时间】:2014-08-15 10:53:34
【问题描述】:

我使用过的所有浏览器都允许使用id="myDiv" 访问元素,只需编写:

myDiv

请看这里:http://jsfiddle.net/L91q54Lt/

无论如何,这种方法似乎记录得很差,事实上,我遇到的来源甚至都没有提及它,而是假设有人会使用

document.getElementById("myDiv")

或许

document.querySelector("#myDiv")

访问一个 DOM 元素,即使它的 ID 是预先知道的(即不在运行时计算)。我可以说,如果有人无意中尝试在更广泛的范围内重新定义myDiv(虽然这不是一个绝妙的主意......),后一种方法具有保持代码安全的优势,用一些不同的值覆盖它并且继续没有注意到冲突。

但除此之外呢?除了代码设计之外,使用上面的简短形式是否有任何顾虑,或者我在这里还缺少什么?

【问题讨论】:

  • 一个窗口属性(如myDiv)可以是任何东西(注意它可能会被覆盖),但getElementById返回HTMLElement(无论属性的值如何)
  • @Jack:这个问题没有提到通过全局变量访问带有 ID 的 HTML 元素,这就是这个问题的意义所在。所以我不认为“高度相关”是完全正确的。
  • @Jack:也许吧。我认为找到那个副本比写答案要付出更多的努力。请注意,重复的问题只提出了该问题在最后一句话中提出的问题。在阅读它及其答案时,您必须先阅读最初的内容(所有浏览器都支持此功能吗?),然后才能回答这个问题(为什么这样做是个坏主意?)。 “不要重复自己”是编程的一个重要原则。它不是一个普遍的常数。重复并不总是邪恶的。
  • @Jack:啊,应得的荣誉。 “第一!”的合法战利品。是的,值得去做。但是,如果回答很快,那么 OP 会很快得到他们的答案,如果类似问题的措辞不同,我认为这意味着再次提出相同问题的人更有可能在自动搜索中得到匹配。跨度>

标签: javascript dom getelementbyid


【解决方案1】:

无论如何,这种方法似乎记录得很差,事实上,我遇到的消息来源甚至都没有提及它[...]

除了依赖隐式声明的全局变量之外,缺乏文档是不使用它的一个重要原因。

id 值明显提升为全局变量不符合标准(HTML5 spec for the ID attribute 没有提及),因此,您不应假设未来的浏览器会实现它。罢工>

编辑:事实证明这种行为 符合标准 - 在 HTML5 中,window 应该支持对“命名元素”的属性访问:

出于上述算法的目的,具有名称 name 的命名对象是:

  • 名称为name的活动文档的子浏览上下文,
  • a、applet、area、embed、form、frameset、img 或具有 名称内容属性,其值为 name,或
  • 具有 id 内容属性的 HTML 元素,其值为 name

来源:HTML 5 spec, 'Named access on window object"强调我的

基于此,标准合规性并不是避免这种模式的理由。但是,规范本身建议不要使用它:

作为一般规则,依赖它会导致代码脆弱。哪一个 最终映射到此 API 的 ID 可能会随着时间的推移而变化,因为新功能是 例如,添加到 Web 平台。而不是这个,使用 document.getElementById()document.querySelector()

【讨论】:

  • 为什么规范会指定一些东西然后建议不要使用它?!好像网络需要更多不好的做法。 #facepalm#
  • 我猜想这是一种形式化支持已被普遍使用的遗留模式的方式。
  • AFAIK name != id (必须),我从未找到任何文档明确指出您不能拥有一个 name="foo" 元素和另一个 id="foo" 元素(可能错过了),所以多一级的歧义。我没有看到 name 和 id 的意义——直到将它们分开破坏了 GTK3 的 API(特别是 gtkbuilder xml UI)中的一堆东西。
  • @Izkata 我知道,你宁愿从别人的错误中吸取教训。大部分 gtkbuilder 和 gtk3 样式都是以 html 和 css 为模型的,然后当他们决定 javascript 将成为构建 gtk3 应用程序的第一类语言时,他们修改了 name~=id 的旧行为并破坏了很多东西.. . 将 name 和 id 作为全局变量引用的能力非常相似,我怀疑在未来的版本中 name 完全消失或 name 得到全局处理(非 js 浏览器的许多遗留形式都依赖于它)和 id需要被收购(只是猜测)。
  • 鉴于编辑和更新,我没有理由不使用此功能。
【解决方案2】:

很好的问题。正如爱因斯坦可能没有说的那样,事情应该尽可能简单,而不是简单。

如果有人无意中尝试在更广泛的范围内重新定义 myDiv(虽然这不是一个绝妙的主意......),后一种方法的优点是可以保持代码安全,用一些不同的值覆盖它并继续而不注意到冲突

这就是为什么这是一个坏主意的主要原因,而且已经足够了。依赖全局变量并不安全。它们可以随时被最终在页面上运行的任何脚本覆盖。

除此之外,仅仅输入myDiv 并不是document.getElementById() 的“缩写形式”。这是对全局变量的引用。如果元素不存在,document.getElementById() 将愉快地返回 null,而尝试访问不存在的全局变量将引发引用错误,因此您需要包装您的引用到全局的 try/catch 块是安全的。

这是 jQuery 如此受欢迎的原因之一:如果你使用 $("#myDiv").remove(),并且没有 id 为 myDiv 的元素,则不会抛出任何错误——代码只会默默地什么都不做,这通常是正是您在进行 DOM 操作时想要的。

【讨论】:

  • document.getElementById() 如果元素不存在则返回null,而不是undefined
  • @GOTO0:哦,干杯干杯,我知道我应该检查一下。
  • 无声的失败,讽刺的是,这也是人们不喜欢 jQuery 的原因之一。
  • @RyanKinal 快速失败,失败便宜。这就是我经常说的。
【解决方案3】:

有几个原因:

你不希望你的代码和你的标记耦合在一起。

通过使用特定调用来访问 div,您不必担心全局空间被破坏。添加一个在全局空间中声明 myDiv 的库,您将处于一个难以修复的痛苦世界中。

您可以通过 ID 访问不属于 DOM 的元素

它们可以位于已分离但尚未重新附加到 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);

【讨论】:

  • 看来你错了:Firefox 和 Chromium 都不允许我通过 ID 访问不属于 DOM 的元素。至少是分离的。
  • @user 您无法使用document.getElementById 访问它们,但是,我更新了我的答案以显示如何通过id 访问span,在documentFragment 内。
【解决方案4】:

就我而言,我的页面中有一个 iframe。我对id 属性和name 属性感到困惑,这两者都影响了一个名为inner_iframe 的变量,可以从window 访问!

  • 如果我只使用 id 属性,比如id="inner_iframe"window.inner_iframe 就是HTMLIFrameElement。属性包括inner_iframe.contentDocumentinner_iframe.contentWindowas described here*

  • 如果我只使用 name 属性,比如name="inner_iframe",那么window.inner_iframe 就是一个“框架”,也就是"window object"contentWindow,因此名称属性 inner_iframe 具有 contentDocumentcontentWindow 属性。

  • 如果我使用两个 nameid 属性,我给这两个属性相同的值name="inner_iframe" id="inner-iframe"name 属性胜过/破坏了id 属性;我留下了“窗口对象”,不是HTMLIFrameElement

所以我的意思是要小心歧义; nameid 属性在具有两个不同 API 的同一对象上的冲突:只是隐式行为和对窗口变量的附加可能会使您感到困惑的特定情况。

*(并且仅当<script> 在 HTML 中的 <iframe> 之后/下方加载,或者 <script> 等到 window.onload 之后才尝试通过 id 属性访问)

**此“框架”与 DOM 元素的区别在 Mozilla 文档中描述为:

window.frames 伪数组中的每一项都表示对应于给定 's 或 ' 内容的窗口对象,不是 (i)frame DOM 元素(即 window.frames[ 0] 与 document.getElementsByTagName("iframe")[0].contentWindow) 相同。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-05-11
    • 1970-01-01
    • 2011-08-28
    • 2011-12-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多