为什么我们不直接使用元素 ID 作为 JavaScript 中的标识符?

IT技术 javascript dom getelementbyid
2021-02-04 14:42:40

我使用过的所有浏览器都允许id="myDiv"通过简单地编写来访问元素

myDiv

见这里:http : //jsfiddle.net/L91q54Lt/

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

document.getElementById("myDiv")

或许

document.querySelector("#myDiv")

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

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

4个回答

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

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

id明显提升为全局变量不符合标准(ID 属性HTML5 规范没有提到它),因此,您不应该假设未来的浏览器会实现它。

编辑:原来,这种行为符合标准-在HTML5中,window应该支持“命名元素”访问属性:

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

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

来源:HTML 5 规范,“窗口对象的命名访问”重点是我的

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

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

@Izkata 我知道,您不想从其他错误中学习吗。许多 gtkbuilder 和 gtk3 样式都是在 html 和 css 之后建模的,然后当他们决定 javascript 将成为构建 gtk3 应用程序的第一类语言时,他们修改了旧的行为,即 name~=id 并破坏了很多东西.. . 将 name 和 id 都引用为 globals 的能力非常相似,我怀疑在未来的版本中,要么 name 完全消失,要么 name 得到全局处理(非 js 浏览器的许多遗留表单依赖于它)和 id需要被收购(只是猜测)。
2021-03-16 14:42:40
AFAIK name != id(必然),我从来没有发现任何文档明确说明你不能有一个 name="foo" 的元素和另一个 id="foo" 的元素(可能已经错过了),所以还有 1 个级别的歧义。我没有看到 name 和 id 的重点——直到将它们分开破坏了 GTK3 的 API(特别是 gtkbuilder xml UI)中的一堆东西。
2021-03-21 14:42:40
我猜想作为一种形式化支持已经落入普通(ish)用法的遗留模式的方式。
2021-03-22 14:42:40
为什么规范会指定一些东西然后建议不要使用它?!好像网络需要更多不好的做法。#面掌#
2021-03-27 14:42:40
鉴于编辑和更新,我没有看到不使用此功能的理由。
2021-03-29 14:42:40

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

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

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

除此之外,仅仅输入myDiv不是document.getElementById(). 它是对全局变量的引用。如果元素不存在,它document.getElementById()会很高兴地返回null,而尝试访问一个不存在的全局变量将抛出一个引用错误,因此您需要将您对全局变量的引用包装在 try/catch 块中以确保安全。

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

@RyanKinal 失败快,失败便宜。这就是我常说的。
2021-03-16 14:42:40
@GOTO0:哦,欢呼声,我知道我应该检查一下。
2021-03-25 14:42:40
讽刺的是,无声的失败也是人们不喜欢 jQuery 的原因之一。
2021-03-29 14:42:40
document.getElementById()null如果元素不存在则返回,不存在undefined
2021-04-05 14:42:40

有几个原因:

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

通过使用特定调用来访问 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);

@user 您无法使用 访问它们document.getElementById,但是,我更新了我的答案以显示如何访问 a span、 by id、 a 的内部documentFragment
2021-03-15 14:42:40
看起来你错了:Firefox 和 Chromium 都不允许我通过 ID 访问不属于 DOM 的元素至少是分离的。
2021-03-26 14:42:40

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

  • 如果我只使用id 属性,比如id="inner_iframe"window.inner_iframe就是一个HTMLIFrameElement. 属性包括inner_iframe.contentDocumentinner_iframe.contentWindow 如此处所述*

  • 如果我只使用name 属性name="inner_iframe"那么就像window.inner_iframe一个“框架”,又名“窗口对象”contentWindow,故而得名属性inner_iframe并没有具有属性contentDocumentcontentWindow

  • 如果我用这两个 nameid属性,我给这两个属性的值相同name="inner_iframe" id="inner-iframe"; name属性捏造/重挫的id属性; 我被留下的“窗口对象”,不是HTMLIFrameElement

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

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

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

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