在某些浏览器中,当你将一个DOM对象的引用作为属性放在该DOM对象上时,就会出现循环引用问题。这样,你就有两个互相指向的DOM对象。删除一个具有自定义属性的DOM对象并不会清除该自定义属性。如果垃圾收集器不够聪明,则无法意识到该DOM引用不计入其中,因此它会被卡住,这可能会导致内存泄漏。
`.data()` 解决了这个问题,因为 `.data()` 数据不在 DOM 对象上。它只是一个 JavaScript 数据结构,可以通过唯一的字符串 ID 与 DOM 对象关联起来。
其中一个令人困惑的部分是,当您使用 ` .data("key")` 读取时,如果 JavaScript 的 `.data()` 数据结构中没有找到 `key`,那么只有 jQuery 才会查找名为 `"data-key"` 的 DOM 对象上的属性。但是,每当你使用 ` .data("key", "myData")` 写入数据时,它永远不会写入 DOM 对象,而只是写入 JavaScript 数据结构。
因此,由于 `.data()` 永远不会将数据写入 DOM 对象,因此就不可能存在浏览器难以处理的这些类型的循环引用。
还有一些关于 `.data()` 数据结构有用的知识点。当使用 jQuery 的 ` .remove()` 从 DOM 中删除元素或调用 `$(elem).html("new html")` 时,jQuery会清除任何已删除项上的 `.data()` 数据。这是一个情况下,最好不要将 jQuery 与纯JavaScript混合使用。如果您正在使用 ` .data()`,那么应始终使用 jQuery 函数从 DOM 中删除项目,以便适当地清除 `.data()`。否则,这样可能会导致内存泄漏(`.data()` 数据和在 `.data()` 中引用的任何已删除DOM对象都可能会泄漏)。但是,如果只使用 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")
,并观察其工作方式。
.data()
存储多少以MB或KB
为单位的数据吗? - EaBengaluru