考虑这个简单的页面:
<html>
<head>
<script>
var upper;
var lower;
function crop() {
//upper = document.getElementById('upper');
lower = document.getElementById('lower');
document.body.innerHTML = '';
document.body.appendChild(lower.cloneNode(true));
}
function up() {
document.body.innerHTML = '';
document.body.appendChild(lower.parentNode);
}
</script>
</head>
<body>
<div id="upper">
Upper Div
<div id="lower">
Lower Div
<button onclick="crop()">Crop</button>
<button onclick="up()">Up</button>
</div>
</div>
</body>
</html>
所以Crop
按钮清除身体,克隆下部div并将其附加到身体上。 Up
按钮的目的是使下div的父级可见(upper
div)。在我的第一次尝试中,我尝试使用lower.parentNode
,这不起作用,因为它是null
。我认为这是因为变量lower
现在指向一个DOM元素,它不是正文的一部分。 (我的理解是否正确?)但现在考虑注释行:
//upper = document.getElementById('upper');
除了获得对上部div的引用之外什么都不做。当我取消注释此行时,up()
开始工作。这里奇怪的是我没有以任何方式使用这个变量。你能解释一下这种行为吗?
答案 0 :(得分:3)
当您设置document.body.innerHTML = '';
时,您将从 DOM树中删除<body>
的所有子节点,但不会破坏这些节点本身的树结构。如果没有对这些节点的引用,它们也会被销毁并收集垃圾。
您已设置(全局) lower = document.getElementById('lower');
,因此存在对<div id="lower">
的引用,这意味着虽然它可能会从 DOM树中删除< / em>,它不会被破坏或被垃圾收集,因为它被这个引用“保持活着”。
现在出现了奇怪的东西,因为你将 String 方法(.innerHTML
)与 DOM 方法混合在一起(getElementById
,{{ 1}}),浏览器不确定从垃圾收集中保存什么。它最终决定appendChild
引用的节点可以保留,但childNodes
s不是足够强的键,因此被破坏。这意味着你不能统一获得parentNode
,你也可以获得
null
当您设置(全局) Uncaught Error: NotFoundError: DOM Exception 8
时,这会保存upper
,因为您现在有一个引用使其保持活动状态。它还会保存<div id="upper">
,因为<div id="lower">
的{{1}}也可以免受垃圾回收。这会保留它们之间的 childNode / upper
链接。
值得注意的是,childNode
可能会导致 id 属性冲突,因为 id 必须是唯一的,但根据定义,克隆不是唯一的。
答案 1 :(得分:1)
您创建一个名为 upper 的全局变量。当您运行 crop 时,您将为id upper 的元素分配一个引用,该元素存储为全局,并且仍然可用作引用该元素的全局变量,无论您是什么做DOM。
为了进一步解释,通过保留 upper ,您还保留其所有后代及其关系,因此在清除正文后 lower.parentNode 仍然存在。但是如果你没有保留对 upper 的引用,那么清除正文也删除 lower 的任何父级或兄弟,但不删除 lower 的后代。