10

我已经阅读了为什么它更好以及它是如何实现的。但我真正不明白的是它是如何破坏循环引用的?.

它是如何打破参考圈的?

$(div1).data('item', div2);
$(div2).data('item', div1);

例如,上面的div相互指向,如何防止?我有预感,但我只是想确定我的预感是否正确。

4

1 回答 1

15

当您将对 DOM 对象的引用作为该 DOM 对象的属性时,在某些浏览器中会发生循环引用问题。然后,您有两个相互指向的 DOM 对象。移除带有自定义属性的 DOM 对象并不会清除该自定义属性。不那么聪明的垃圾收集器没有意识到这个 DOM 引用不计数,因此它被卡住了,并且有几种方法可能导致泄漏。

.data()解决了这个问题,因为.data()数据不在 DOM 对象上。它只是一个 javascript 数据结构,可以通过唯一的字符串 ID 与 DOM 对象相关联。

一个令人困惑的部分是,当您阅读时.data("key")keyjavascript 数据结构中没有找到.data(),然后,只有这样,jQuery 才会在 DOM 对象上查找名为"data-key". 但无论何时使用 编写.data("key", "myData"),它都不会写入 DOM 对象,只会写入 javascript 数据结构。

因此,由于.data()从不将数据写入 DOM 对象,因此不会存在某些浏览器遇到问题的任何这些类型的循环引用。

.data()关于数据结构,还有一些其他有用的信息需要了解。当您使用 jQuery.remove()从 DOM 中删除元素或调用 时$(elem).html("new html"),jQuery 会清除.data()所有已删除项上的数据。这是一种最好不要将 jQuery 与纯 javascript 混合的情况。如果您正在使用.data(),那么您应该始终使用 jQuery 函数从 DOM 中删除项目,以便.data()适当地清理。否则,您可能会以这种方式获得内存泄漏(.data()数据可能泄漏以及在可能泄漏中引用的任何已删除 DOM 对象.data()。但是,如果您仅使用 jQuery 方法从 DOM 中删除项目(包括替换 innerHTML),然后 jQuery 会适当地清理东西并且不会有泄漏。

因此,例如,这将造成内存泄漏:

// suppose elem is a DOM element reference

// store some data in jQuery's data storage on behalf of a DOM element
$(elem).data("someKey", "someValue");

// remove DOM element with plain Javascript
elem.parentNode.removeChild(elem);

因为您使用纯 Javascript 删除了 DOM 元素,所以 jQuery 没有机会清理您之前存储的数据。DOM 元素本身将被垃圾回收,但.data()您之前存储的值现在在 jQuery 的存储中是孤立的,本质上是一个“泄漏”,因为它可能永远不会被清除。另一方面,如果你这样做:

$(elem).data("someKey", "someValue");
$(elem).remove();

然后,jQuery 将看到您正在删除 DOM 元素,并且还会清除您使用.data().

了解其工作原理的一种相当简单的方法是使用非最小化版本的 jQuery 创建一对行脚本,然后$(elem).data("key", "whatever")在调试器中逐步调用并观察它是如何工作的。

于 2012-04-04T03:46:20.467 回答