为啥元素从 DOM 中移除后仍可访问?

Posted

技术标签:

【中文标题】为啥元素从 DOM 中移除后仍可访问?【英文标题】:Why is an element accessible even after being removed from DOM?为什么元素从 DOM 中移除后仍可访问? 【发布时间】:2015-12-13 08:59:19 【问题描述】:

window.a = 
  div1: $('#div1'),
  img1: $('#img1')
;

$(a.img1).click(function() 
  a.div1.html('<img id="img2" src="https://www.gstatic.com/webp/gallery/2.sm.jpg" />');
  $('#img2').click(function() 
    $(a.img1).attr('src', 'https://www.gstatic.com/webp/gallery/3.sm.jpg');
  );
);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<div id="div1">
  <img id="img1" src="https://www.gstatic.com/webp/gallery/1.sm.jpg" />
</div>

当第 9 行执行时,即第二次单击图像时$(a.img1).attr('src', 'https://www.gstatic.com/webp/gallery/3.sm.jpg');,a.img1 不应该存在。那么,为什么该 URL 的 HTTP 请求被发送到服务器(网络选项卡中的通知)?我正在使用 Chrome 版本 45.0.2454.85 m。不要认为这是一个浏览器错误。也适用于 Firefox 39。

还做了一个提琴手http://jsfiddle.net/ismusidhu/vvmwntcd/。

【问题讨论】:

您已经从 DOM 树中删除了该节点,但它仍然存在,因为 window.img1 仍然指向它 - 所以它不能被垃圾回收。 “为什么元素从 DOM 中移除后仍然可以访问?”DOM 中移除的元素在哪里? @guest271314 a.div1.html() 应该删除它。不是吗? @IsmailS 是的,你是对的;从DOM 中删除,但仍然是window.a.img1 处的jQuery 对象 如果你从酒店房间偷了遥控器,当你按下按钮时它仍然会闪烁灯,即使它不会对任何其他电视做任何事情...... 【参考方案1】:

作为Marc B said,您已经从DOM 树中删除了该节点,但它仍然存在,因为window.img1 仍然指向它(间接地,通过指向一个反过来指向它的jQuery 对象)——所以它不能被垃圾回收。如果将window.img1 设置为不同的值(例如nullundefined),则可以对元素进行垃圾回收。

这样想:你从指向它的图像的父元素(以及各种兄弟元素,但暂时忽略它)开始:

+------------------+ +------------------+ | (一些 DOM 元素)|---------->| | +---------------------+ | | |图像元素| +--------+ | | | img1 |------------>| | +------+ +------------------+

然后,当您在其祖先上调用 html 时,DOM 会删除对该元素的所有引用,并且您会得到:

+-------------------+ | | | | |图像元素| +--------+ | | | img1 |------------>| | +------+ +------------------+

释放最后一个引用,元素可以被回收/释放。

【讨论】:

这是一个真实的答案,那你为什么把它作为社区维基? @IsmailS:CW 是真正的答案。当我看到有人评论了(一个​​不完整的版本)如果答案很短,我会回答什么时,我经常勾选 CW 框。我不关心代表,这似乎有助于避免抱怨从 cmets 那里“偷走”他们的“答案”。 (我不认为 Marc B 会那样抱怨,但我是从别人那里得到的,所以......) 那是您的伟大,先生!无论如何,如果有人抱怨窃取答案,那一定是他们的错。你已经详细说明了。他们没有。 ;)【参考方案2】:

window.a = 
  div1: $('#div1'),
  img1: function() 
    return $("> img[id]", this.div1)
  
;

function toggle(e) 
  a.div1.html(/1/.test(e.target.src) 
             ? '<img id="img2" src="https://www.gstatic.com/webp/gallery/2.sm.jpg" />' 
             : $('<img id="img1" src="https://www.gstatic.com/webp/gallery/1.sm.jpg" />')
               .click(toggle)
  );
  
  $("#img2").on("click", function(e) 
    a.img1().attr(
        'src': 'https://www.gstatic.com/webp/gallery/3.sm.jpg',
        "id": "img3"
      )
      .click(toggle)
  );


a.img1().click(toggle);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<div id="div1">
  <img id="img1" src="https://www.gstatic.com/webp/gallery/1.sm.jpg" />
</div>

jsfiddle http://jsfiddle.net/vvmwntcd/6/

【讨论】:

浏览器仍然向https://www.gstatic.com/webp/gallery/3.sm.jpg发出请求。在网络选项卡上检查。控制台确实显示undefined @IsmailS:控制台显示undefined 的唯一原因是代码输出a.img 而不是a.img1。这样做is 检查 before 元素被删除并不会让它在以后神奇地消失。如果你使用corrected version,你会看到a.img1仍然是一个jQuery对象(当然),a.img1[0]仍然有一个HTMLInputElement对象的引用(当然)。 @IsmailS:你的问题的答案是 Marc B 早先所说的:它仍然存在,因为仍然有对它的引用。在显示图像之前使用断开连接的img 获取图像是一种常用技术。为避免这种情况发生,请清除 img1

以上是关于为啥元素从 DOM 中移除后仍可访问?的主要内容,如果未能解决你的问题,请参考以下文章

SKSpriteNode 从场景中移除后如何停止音频(Swift)?

CALayer 帧值即使在从超级层中移除后也会导致动画

从 DOM 中移除的元素中取消绑定事件

移除元素

从 DOM 数组中移除 DOM 对象

guava cache 为啥删除元素时移动元素