html 带有ID的DOM树元素会成为全局属性吗?

yc0p9oo0  于 2023-05-21  发布在  其他
关注(0)|答案(6)|浏览(176)

在研究一个简单的HTMLElement Package 器的想法时,我偶然发现了Internet Explorer和Chrome的以下内容:
对于DOM树中带有id的给定HTMLElement,可以使用其ID作为变量名或window的属性来检索<div>。对于<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方法?

x759pob2

x759pob21#

应该发生的是,“命名元素”被添加为document对象的明显属性。这是一个非常糟糕的想法,因为它允许元素名称与document的实际属性冲突。
IE还添加了命名元素作为window对象的属性,使情况变得更糟。这是双重的坏,因为现在你必须避免以你(或项目中的任何其他库代码)可能想要使用的documentwindow对象的任何成员来命名你的元素。
这也意味着这些元素可以作为类似全局的变量。幸运的是,在这种情况下,代码中的任何真实的的全局varfunction声明都会隐藏它们,所以你不需要太担心这里的命名,但是如果你试图用一个冲突的名称对一个全局变量进行赋值,而你忘记声明它var,你会在IE中得到一个错误,因为它试图将值赋值给元素本身。
忽略var以及依赖于在window上可见的命名元素或全局元素通常被认为是不好的做法。坚持使用document.getElementById,它得到更广泛的支持,并且不那么模糊。如果你不喜欢这种类型,你可以用一个较短的名字写一个简单的 Package 函数。无论哪种方式,使用id到元素的查找缓存都没有意义,因为浏览器通常会优化getElementById调用以使用快速查找;当元素改变id或从文档中添加/删除时,你得到的只是问题。
Opera复制了IE,然后WebKit加入了进来,现在无论是将命名元素放在document属性上的以前非标准化的做法,还是将它们放在window上的以前只有IE的做法,都被HTML5标准化了,HTML5的方法是记录和标准化浏览器作者强加给我们的每一个可怕的做法,使它们永远成为网络的一部分。Firefox 4也支持这个功能。
什么是“命名元素”?任何带有id的东西,以及任何带有name的东西都被用于“识别”目的:也就是说,表单、图像、锚点和其他一些,但不是name属性的其他不相关的示例,如表单输入字段中的控件名称、<param>中的参数名称或<meta>中的元数据类型。“识别”name s是应该避免的,而应该支持id

dl5txlt9

dl5txlt92#

正如前面的回答中所提到的,这种行为称为对窗口对象的命名访问。某些元素的name属性值和所有元素的id属性值可用作全局window对象的属性。这些元素称为命名元素。由于window是浏览器中的全局对象,因此每个命名元素都可以作为全局变量访问。
这最初是由Internet Explorer添加的,最终被所有其他浏览器实现,只是为了与依赖此行为的网站兼容。有趣的是,Gecko(Firefox的渲染引擎)选择只在quirks mode中实现它,而其他渲染引擎则在标准模式中保留它。
但是,从Firefox 14开始,window对象上的Firefox now supports named access也处于标准模式。他们为什么要改变这个?事实证明,仍然有很多网站在标准模式下依赖此功能。微软甚至做了released a marketing demo,阻止演示在Firefox中工作。
Webkit最近更新了considered the opposite,将window对象上的命名访问降级为quirks模式。他们决定反对它的理由和壁虎一样。
所以......疯狂的是,这种行为现在在技术上是安全的,可以在标准模式下在所有主要浏览器的最新版本中使用。但是,虽然命名访问看起来有些方便,但不应该使用
为什么?很多推理可以在这篇文章中总结出来为什么是global variables are bad。简单地说,拥有一堆额外的全局变量会导致更多的bug。假设你不小心输入了一个var的名字,而碰巧输入了一个DOM节点的id,惊喜!
此外,尽管已经标准化,但在浏览器的命名访问实现中仍然存在相当多的差异。

  • IE错误地使name属性的值可用于表单元素(input、select等)。
  • Gecko和Webkit不正确地使<a>标签通过其name属性可访问。
  • Gecko错误地处理多个同名的命名元素(它返回一个对单个节点的引用,而不是一个引用数组)。

如果您尝试在边缘情况下使用命名访问,我相信还会有更多。
正如在其他答案中提到的,使用document.getElementById通过id获取对DOM节点的引用。如果需要通过name属性获取对节点的引用,请使用document.querySelectorAll
请不要通过在您的站点中使用命名访问来传播此问题。许多Web开发人员浪费时间试图追踪这种“神奇的”行为。我们真的需要采取行动,让渲染引擎在标准模式下关闭命名访问。在短期内,它会打破一些网站做坏事,但从长远来看,它将有助于推动网络向前发展。
如果你感兴趣,我会在我的博客https://www.tjvantoll.com/2012/07/19/dom-element-references-as-global-variables/上详细讨论这个问题。

xam8gpfp

xam8gpfp3#

在这些情况下,您应该坚持使用getElementById(),例如:

document.getElementById('example').innerHTML

IE喜欢在全局命名空间中混合使用具有name * 和 * ID属性的元素,因此最好明确说明您想要获取的内容。

zz2j4svz

zz2j4svz4#

这个问题听起来应该是:“带有提供的ID的HTML标签会成为全局可访问的DOM元素吗?“
答案是肯定的!
这就是它的工作方式,这就是W3C开始引入ID的原因。* 解析脚本环境中的HTML标记的ID将成为其对应的DOM元素句柄。*
然而,Netscape Mozilla拒绝遵守W3C,并顽固地使用已弃用的Name属性来制造混乱,因此破坏了W3C引入Unique ID带来的脚本功能和编码便利。
在Netscape Navigator 4.7惨败之后,他们的开发人员都渗透到了W3C,而他们的同事则用错误的做法和滥用的例子取代了Web。强制使用和重用已弃用的Name属性[!这并不意味着是唯一的]与ID属性相提并论,这样使用ID句柄访问特定DOM元素的脚本就会崩溃!
他们还编写并发布了大量的编码课程和示例[他们的浏览器无论如何都无法识别],例如document.all.ElementID.property而不是ElementID.property,以至少使其效率低下,并给予浏览器更多的开销,以防它不只是在HTML域中使用相同的令牌来破坏它。(现在[1996-97],已弃用)名称和标准ID属性,为它提供相同的标记值。
他们轻而易举地说服了当时大量无知的代码编写业余爱好者,让他们相信Name和ID实际上是一样的,只是ID属性更短,因此比古老的Name属性更节省字节,对编码者来说更方便。这当然是个谎言。或者-在它们取代HTML的已发布文章中,说服文章,您需要为标记提供Name和ID,以便脚本引擎可以访问它们。
Mosaic Killers(代号“Mozilla”)非常生气,他们认为“如果我们倒下了,互联网也应该倒下”。
另一方面,崛起的微软是如此天真,他们认为他们应该保留已弃用并标记为删除的Name属性,并将其视为一个ID,这是一个唯一的标识符,这样他们就不会破坏Netscape学员编写的旧页面的脚本功能。他们大错特错了
返回ID冲突元素的数组集合也不是这个故意人为问题的解决方案。事实上,它击败了整个目的。
这就是W3C变得丑陋的唯一原因,给我们带来了像document.getElementById这样的白痴,以及随之而来的洛可可式的讨厌的语法。(...)

5ssjco0h

5ssjco0h5#

是的他们会

已在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

a11xaf1n

a11xaf1n6#

**document.all**需要重新使用,并进行一些修复

idname的元素在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

相关问题