为啥这个 HTML 标记在加载正文之前就将正文作为它的 lastChild

Posted

技术标签:

【中文标题】为啥这个 HTML 标记在加载正文之前就将正文作为它的 lastChild【英文标题】:Why is this HTML tag has body as its lastChild even before the body is loaded为什么这个 HTML 标记在加载正文之前就将正文作为它的 lastChild 【发布时间】:2017-07-06 02:04:53 【问题描述】:

我感觉这可能与对象引用有关,但这里是:

我有以下代码:

<html>
    <head>
        <script type="text/javascript">
            console.log(document.getElementsByTagName("html"));
            console.log(document.getElementsByTagName("html")[0].lastChild);
       </script>
   </head>

   <body><h1>Hello</h1></body>
</html>

在控制台中,当我展开第一个返回的集合时,我可以看到它有 body 作为其子节点 (lastChild),即使 body 元素尚未被解析。但在第二个对象中,它显示了 head 标记,这是预期的。

现在,在这里发布这个问题时,我创建了这个pen,但那里的第二个控制台是主体标签而不是头部。

那么,为什么第一个控制台语句在 html 中显示正文?还是与浏览器有关?谢谢

【问题讨论】:

【参考方案1】:

getElementsByTagName 会给你一个live HTMLCollection。这意味着,当底层 DOM 发生变化时,函数返回的实时集合也会发生变化。

HTML DOM 中的 HTMLCollection 是活动的;它会在基础文档更改时自动更新。

https://developer.mozilla.org/en-US/docs/Web/API/HTMLCollection

所以最初,在记录发生时,body 标记仍未被解析。如果您可以在解析正文之前检查控制台输出,您就不会在那里看到它。

但是当您真正在控制台中检查 HTMLCollection 时,body 已经被解析并因此被显示(因为 HTMLCollection 再次处于活动状态)。

如果您想“中断”实时连接,您可以使用数组扩展运算符将 HTMLCollection 转换为标准数组:

const collection = [...liveCollection];

很明显,第二个 console.log 打印了 head 标签,因为当它被记录时,它确实是最后一个孩子。

仅供参考

getElementsByClassName 等其他常见的 DOM 查询函数也为您提供实时集合。

【讨论】:

我认为你的答案是正确的。我刚刚添加了我的,因为你的有点令人困惑。也许你可以用更多的解释来更新你的 querySelectorAll() 返回静态集合,而不是实时集合。 这与是否liveCollection无关...只是一般来说,当您扩展控制台中记录的对象时,您会获得其当前状态,而不是当前状态已被记录...您可以记录document.documentElement 并获得完全相同的结果...【参考方案2】:

正如@scarySize 提到的,当您在第一个console.log 上记录html 标记时,它实际上记录了实时HTMLCollection。

所以最初,在记录发生时,body 标记仍未被解析。因此,如果您可以在解析正文之前检查控制台输出,您就不会在那里看到它。

但是当您真正在控制台中检查 HTMLCollection 时,body 已经被解析并因此被显示(因为 HTMLCollection 再次处于活动状态)。

很明显,第二个console.log 打印头标签,因为在它被记录时,它确实是最后一个孩子。

【讨论】:

以上是关于为啥这个 HTML 标记在加载正文之前就将正文作为它的 lastChild的主要内容,如果未能解决你的问题,请参考以下文章

如何使用联系表格 7 在邮件正文中发送 HTML 内容?

GWT:在页面准备好之前开始运行(或者正文资源不会阻止运行 gwt)?

奇怪的 IE8 布局故障 - 为啥正文背景消失了?

laravel-push-notification 在响应正文中返回 html 标记

页面加载完成后执行javascript [重复]

头部中的 Angularjs 组件被渲染到正文中