3

考虑这个简单的页面:

<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 的父级可见 ( upperdiv)。在我的第一次尝试中,我尝试使用lower.parentNode,它不起作用,因为它是null. 我认为这是因为变量lower现在指向一个 DOM 元素,它不是主体的一部分。(我的理解正确吗?)但现在考虑注释行:

//upper = document.getElementById('upper');

除了获取对上层 div 的引用之外,它什么也不做。当我取消注释此行时,up()开始工作。这里奇怪的是我没有以任何方式使用这个变量。你能解释一下这种行为吗?

4

2 回答 2

3

设置时document.body.innerHTML = '';,您<body>将从DOM 树中删除所有子节点,但不会破坏这些节点本身的树结构。如果不存在对这些节点的引用,它们也会被销毁并被垃圾收集。

您已设置(global) lower = document.getElementById('lower');,因此存在对 的引用<div id="lower">,这意味着尽管它可能会从DOM 树中删除,但它不会被破坏或垃圾收集,因为它被此引用“保持活跃”。

现在奇怪的东西来了,因为您将字符串方法 ( .innerHTML) 与DOM方法 ( getElementById, appendChild) 混合在一起,浏览器不确定要从垃圾收集中保存什么。它最终决定childNodes被引用的节点可以保留,但parentNodes 的结合力不够强,所以被摧毁。这意味着你不统一得到null,你也可以得到

Uncaught Error: NotFoundError: DOM Exception 8 

当您设置(global) upper时,这将保存<div id="upper">,因为您现在有一个引用使其保持活动状态。它也节省了s <div id="lower">,因为s 也受到了垃圾收集的保护。这保留了它们之间的childNode /链接。upperchildNodeparentNode


还值得注意的是,cloneNode可能会导致id属性冲突,因为id必须是唯一的但根据定义,克隆不是唯一的

于 2013-06-25T22:05:43.133 回答
1

您创建一个名为upper的全局变量。当你运行crop时,你分配一个对 id为upper的元素的引用,它被存储为一个全局变量,并且无论你对 DOM 做了什么,它仍然作为一个引用该元素的全局变量可用。

编辑

进一步解释一下,通过保留upper,您还保留了它的所有后代及其关系,因此在您清除 body 后lower.parentNode仍然存在。但是如果你不保留对upper的引用,那么清除 body 也会删除lower的任何父级或兄弟级,但不会删除lower的后代。

于 2013-06-25T22:02:27.887 回答