提问人:KooiInc 提问时间:8/8/2010 最后编辑:Sebastian SimonKooiInc 更新时间:5/16/2023 访问量:57052
带有 ID 的 DOM 树元素会成为全局属性吗?
Do DOM tree elements with IDs become global properties?
问:
在为一个简单的包装器构想时,我偶然发现了以下适用于 Internet Explorer 和 Chrome 的内容:HTMLElement
对于在 DOM 树中带有 的给定,可以使用其 ID 作为变量名或属性来检索 。所以对于一个喜欢HTMLElement
id
<div>
window
<div>
<div id="example">some text</div>
在 Internet Explorer 8 和 Chrome 中,您可以执行以下操作:
alert(example.innerHTML); // Alerts "some text".
或
alert(window["example"].innerHTML); // Alerts "some text".
那么,这是否意味着 DOM 树中的每个元素都转换为全局对象上的属性?这是否也意味着人们可以用它来替代这些浏览器中的方法?getElementById
答:
在这些情况下,您应该坚持下去,例如:getElementById()
document.getElementById('example').innerHTML
IE 喜欢将元素与全局命名空间中的 和 属性混合在一起,因此最好明确说明您要获取的内容。name
ID
应该发生的事情是将“命名元素”添加为对象的表观属性。这是一个非常糟糕的主意,因为它允许元素名称与 的实际属性发生冲突。document
document
IE 还通过添加命名元素作为对象的属性,使情况变得更糟。这是双重糟糕的,因为现在您必须避免以您(或项目中的任何其他库代码)可能想要使用的对象的任何成员命名元素。window
document
window
这也意味着这些元素可以作为全局变量显示。幸运的是,在这种情况下,代码中任何真正的全局变量或声明都会隐藏它们,因此您无需太担心此处的命名,但是如果您尝试对具有冲突名称的全局变量进行赋值,并且忘记声明它,则在IE中会遇到错误,因为它试图将值分配给元素本身。var
function
var
通常认为省略 以及依赖命名元素在全局变量上可见或作为全局变量可见是不好的做法。坚持 ,它得到更广泛的支持,不那么模棱两可。如果您不喜欢键入,则可以使用较短的名称编写一个简单的包装函数。无论哪种方式,使用 id 到元素查找缓存都没有意义,因为浏览器通常会优化调用以使用快速查找;当元素更改或从文档中添加/删除时,您得到的只是问题。var
window
document.getElementById
getElementById
id
Opera 复制了 IE,然后 WebKit 也加入了进来,现在,以前将命名元素放在属性上的未标准化做法,以及以前只有 IE 的将命名元素放在属性上的做法,都被 HTML5 标准化了,HTML5 的方法是记录和标准化浏览器作者对我们施加的每一种可怕的做法,使它们永远成为网络的一部分。所以 Firefox 4 也将支持这一点。document
window
什么是“命名元素”?任何带有 ,以及任何带有 a 的东西都用于“识别”目的:即表单、图像、锚点和其他一些,但不包括属性的其他不相关实例,例如表单输入字段中的控件名称、中的参数名称或 中的元数据类型。“识别”是应该避免的,而应该避免。id
name
name
<param>
<meta>
name
id
评论
如前面的答案中所述,此行为称为对窗口对象的命名访问。某些元素的属性值和所有元素的属性值都可用作全局对象的属性。这些元素称为命名元素。由于是浏览器中的全局对象,因此每个命名元素都可以作为全局变量进行访问。name
id
window
window
这最初是由 Internet Explorer 添加的,最终由所有其他浏览器实现,只是为了与依赖于此行为的站点兼容。有趣的是,Gecko(Firefox 的渲染引擎)选择仅在 Quirks 模式下实现这一点,而其他渲染引擎则在标准模式下保持打开状态。
但是,从 Firefox 14 开始,Firefox 现在也支持在标准模式下对对象进行命名访问。他们为什么要改变这一点?事实证明,仍然有很多网站在标准模式下依赖此功能。Microsoft甚至发布了一个营销演示,阻止了该演示在Firefox中工作。window
Webkit 最近考虑了相反的情况,将对对象的命名访问降级为仅 quirks 模式。他们以与 Gecko 相同的推理决定反对它。window
所以。。。看起来很疯狂,这种行为现在在技术上是安全的,可以在标准模式下在所有主要浏览器的最新版本中使用。但是,虽然命名访问似乎有些方便,但不应该使用它。
为什么?在这篇文章中,可以总结出很多关于为什么全局变量不好的推理。简单地说,拥有一堆额外的全局变量会导致更多的错误。假设您不小心输入了 a 的名称,并且碰巧输入了 DOM 节点的 an,SURPRISE!var
id
此外,尽管是标准化的,但浏览器的命名访问实现仍然存在不少差异。
- IE 错误地使表单元素(输入、选择等)的属性值可访问。
name
- Gecko 和 Webkit 错误地无法通过其属性访问标签。
<a>
name
- Gecko 错误地处理了多个同名的命名元素(它返回对单个节点的引用而不是引用数组)。
我敢肯定,如果您尝试在边缘情况下使用命名访问,还会有更多。
如其他答案中所述,用于通过其 .如果需要通过节点的属性获取对节点的引用,请使用 .document.getElementById
id
name
document.querySelectorAll
请不要通过在站点中使用命名访问权限来传播此问题。如此多的 Web 开发人员浪费时间试图追踪这种神奇的行为。我们确实需要采取行动,让渲染引擎在标准模式下关闭命名访问。在短期内,它将破坏一些做坏事的网站,但从长远来看,它将有助于推动网络向前发展。
如果您有兴趣,我会在我的博客上更详细地讨论这个问题 - https://www.tjvantoll.com/2012/07/19/dom-element-references-as-global-variables/。
评论
document.querySelectorAll
document.querySelector
getElementsByClassName
getElementById
是的,他们有。
在 Chrome 55、Firefox 50、IE 11、IE Edge 14 和 Safari 10 中测试,
示例如下:
<!DOCTYPE html>
<html>
<head>
</head>
<body>
<div id="im_not_particularly_happy_with_that">
Hello World!
</div>
<script>
im_not_particularly_happy_with_that.innerText = 'Hello Internet!';
</script>
<!-- Looking at you W3 HTML5 spec group ಠ_ಠ -->
</body>
</html>
http://jsbin.com/mahobinopa/edit?html,output
评论
window
window["first-name"]
问题应该听起来:“具有提供 ID 的 HTML 标签是否成为全局可访问的 DOM 元素?
答案是肯定的!
这就是它的工作方式,这就是为什么 W3C 一开始就引入了 ID:在解析的脚本环境中,HTML 标记的 ID 成为其对应的 DOM 元素句柄。
然而,Netscape Mozilla 拒绝遵守 W3C(对他们进行入侵),并顽固地继续使用已弃用的 Name 属性来制造破坏,从而破坏了 W3C 引入唯一 ID 带来的脚本功能和编码便利性。
在 Netscape Navigator 4.7 惨败之后,他们的开发人员都去渗透到 W3C 中,而他们的同事则用错误的做法和滥用的例子取代了 Web。强制使用和重用已经弃用的 Name 属性 [!,这并不意味着是唯一的] 与 ID 属性相提并论,这样利用 ID 句柄访问特定 DOM 元素的脚本就会中断!
他们这样做了,因为他们也会编写和发布大量的编码课程和示例[他们的浏览器无论如何都不会识别],例如至少使其效率低下并给浏览器更多的开销,以防它没有简单地在HTML域使用相同的令牌来破坏它(现在[1996-97], deprecated) 名称和为其提供相同令牌值的标准 ID 属性。document.all.ElementID.property
ElementID.property
他们轻而易举地说服了当时绝大多数无知的代码编写业余爱好者,他们相信 Names 和 ID 实际上是相同的,只是 ID 属性更短,因此比古老的 Name 属性更节省字节,对编码人员来说更方便。这当然是谎言。或者 - 在他们取代已发布的 HTML 文章中,说服您需要为标记提供 Name 和 ID,以便脚本引擎可以访问它们。
马赛克杀手(代号为“Mozilla”)非常生气,他们认为“如果我们倒下了,互联网也应该倒下”。
另一方面,崛起的Microsoft是如此天真,他们认为他们应该保留已弃用并标记为删除的Name属性,并将其视为唯一标识符的ID,这样他们就不会破坏Netscape学员编码的旧页面的脚本功能。他们大错特错了......
返回 ID 冲突元素的数组集合也不是解决这个故意的人为问题的方法。实际上,它违背了整个目的。
这就是 W3C 变得丑陋并给我们带来白痴的唯一原因,例如伴随的洛可可式该死的烦人语法......
(...)document.getElementById
评论
document.all
需要取消弃用并修复一点
带有 or 的元素可用,这对我来说是令人兴奋的消息。id
name
document.all
然而,从我收集到的内容来看,它被老前辈弃用和唾弃了,但似乎没有人能够提供任何令人信服的理由来永远不使用它,或者至少能够提供足够有力的论据来说明为什么它应该被弃用。all
我正在将它用于一个小的内部工具页面,它完全有效......目前。它确实有问题,但便利性和清洁度不容忽视:
鉴于
<h1 id="welcomeMessage" hidden>Welcome!</h1>
你可以做
document.all.welcomeMessage.hidden = false
与。
document.getElementById('welcomeMessage').hidden = false
document.querySelector('#welcomeMessage').hidden = false
太好了!但是存在一些问题:
- 如果碰巧有多个元素具有相同的(可能,但可以而且应该避免)或(非常可能,但由于复选框组而无法避免),则返回一个,而不是单个
id
name
HTMLCollection
Element
- 如果您出于某种原因尝试获取具有与继承属性(如 或)匹配的 id 或名称的元素,那么您将获得这些对象而不是
__proto__
toString
undefined
- 它不如 快,因此如果您要查询大量元素,则存在性能问题
document.getElementById
一个不错的选择
我决定这样做,我真的不确定我参加派对有多晚,但我很喜欢这个:
const elements = new Proxy({}, {
get(target, prop) {
return document.getElementById(prop) || document.getElementsByName(prop)[0];
}
});
// Clean and direct access to elements just like document.all
elements.welcomeMessage.hidden = false
评论