为何console.log在Chrome/Edge与Firefox中输出结果不同?
为什么不同浏览器中
console.log()输出cloneContents()的结果存在差异? 尝试运行以下代码(在Edge/Chrome或Firefox环境中执行,不要在代码片段内运行),会发现console.log()在不同浏览器中输出结果存在差异,这一现象的原因是什么?
相关代码
JavaScript代码
const para = document.querySelector('p'), text = para.childNodes.item(0), range = document.createRange() range.setStart(text, 0) range.setEnd(text, 1) const clonedContents = range.cloneContents() // - Chrome/Edge - // string: #docment-fragment // - Firefox - // DocumentFragment [] console.log('cloned contents: ', clonedContents) // - Chrome/Edge - // a real #docment-fragment // - Firefox - // DocumentFragment [ #text ] console.log('cloned contents: ', range.cloneContents()) inContentsNode = clonedContents.childNodes.item(0) // without this line, console.log would work as expected para.after(inContentsNode)
HTML代码
<body> <p>a</p> </body>
不同浏览器输出情况
Edge/Chrome

Firefox

原因分析
这是控制台惰性求值特性加上不同浏览器对DocumentFragment的展示逻辑差异共同导致的:
惰性求值的影响:
浏览器的console.log并不会在调用时就完全快照对象的所有状态,而是记录对象的引用。只有当你在控制台中展开对象条目时,才会去读取对象的当前状态。
代码中,第一次console.log(clonedContents)之后,执行了para.after(inContentsNode),把clonedContents里的唯一子节点移到了DOM树中,此时clonedContents变成了空的DocumentFragment。当你在控制台查看这个对象时,读取的已经是修改后的空状态。浏览器展示逻辑差异:
- Chrome/Edge:对于空的DocumentFragment,控制台直接显示字符串形式的
#document-fragment;如果Fragment有内容,则显示可展开的对象结构。第一次log的clonedContents在查看时已为空,所以显示字符串;第二次log的是新创建的未被修改的Fragment,因此显示带有文本节点的可展开对象。 - Firefox:空的DocumentFragment会显示为
DocumentFragment [],有内容时则显示DocumentFragment [ #text ]。第一次log的clonedContents在查看时已被移走子节点,所以显示空数组;第二次log的Fragment未被修改,因此显示包含文本节点的结构。
- Chrome/Edge:对于空的DocumentFragment,控制台直接显示字符串形式的
如果去掉para.after(inContentsNode)这一行,clonedContents的子节点不会被移除,此时在所有浏览器中两次log的结果都会一致,因为对象状态没有后续修改。
内容的提问来源于stack exchange,提问作者kakakali
相关产品推荐
相关产品推荐

