17

我正在使用 jQuery 开发代码,并且需要存储与某些 DOM 元素关联的数据。关于如何使用 html 元素存储任意数据还有很多其他问题,但我更感兴趣的是为什么我会选择一个选项而不是另一个选项。

说,为了极其简化的论点,我想在一个“有趣”的表中存储一个“lineNumber”属性,每行都有一个。

选项 1 是在每个 DOM 元素上设置一个 expando 属性(我希望我正确使用了“expando”这个术语):

$('.interesting-line').each(function(i) { this.lineNumber = i; });

选项 2 是使用 jQuery 的 data() 函数将属性与元素关联:

$('.interesting-line').each(function(i) { $(this).data('lineNumber', i); });

忽略我的示例代码的任何其他缺点,您是否有充分的理由选择一种存储属性的方法而不是另一种?

4

4 回答 4

20

使用$.data将保护您免受内存泄漏。

在 IE 中,当您将 javascript 对象分配给 DOM 元素上的 expando 属性时,跨越该链接的循环不会被垃圾收集。如果你的 javascript 对象持有对 dom 对象的引用,整个循环就会泄漏。由于闭包,完全有可能最终隐藏对 DOM 对象的引用,因此您可能会在没有意识到的情况下泄漏。

设置 jQuery 数据存储以防止形成这些循环。如果您使用它,您将不会以这种方式泄漏内存。您的示例不会泄漏,因为您将原语(字符串)放在 DOM 元素上。但是如果你把一个更复杂的对象放在那里,你就有泄漏的风险。

使用$.data这样您就不必担心了。

于 2011-01-25T20:05:47.960 回答
13

如果您正在创作一个插件,您应该使用$.data. 如果您需要经常存储属性并且很少需要查询 DOM,请使用$.data.

5 年后更新:jQuery 不会根据expando 属性集查询 DOM,并且已经有一段时间没有这样做了。所以使用$.data. 当没有实际用途时,没有理由污染 DOM。

于 2009-07-21T17:45:33.830 回答
2

使用$.data不会修改 DOM。你应该使用$.data. 如果您正在创建一个插件,那么您应该将一个对象$.data与该对象上的属性一起存储,而不是将这些属性中的每一个存储为结构中的不同键/值对$.data

于 2009-07-21T16:18:41.043 回答
0

让我重新表述一下这个问题:两个可用的数据绑定选项之间的实际区别是什么?

其实有三种选择:

$(e).prop('myKey', myValue);
$(e).data('myKey', myValue);
$(e).attr('data-myKey', myValue);

注意:OP 的e.myKey = myValue实际上与该.prop()行相同。

  • 如果您需要的不仅仅是字符串,请使用.prop(),即 expando 属性
  • 如果您需要 DOM/CSS 透明度和/或 HTML 序列化,请使用.attr('data-*')
  • 如果你两个都需要,那你就不走运了
  • 如果您只使用字符串,但不需要 DOM,请继续阅读以权衡利弊
  • 是什么.data()→阅读最后两段

如果你想用序列化的 HTML 传递数据,你需要这个.attr()解决方案。即,每当您使用.innerHTML.html()想要从包含数据的字符串中构造片段时。如果您想使用 CSS 选择器,如elem[data-myKey]. 缺点:只能存储字符串。

如果您不需要您的数据在 DOM 中可见或可用于 CSS 交互.data()并且.prop()可能有效。它们最大的优势是:它们可以保存任何 Javascript 值

.prop()最大的缺点是名字冲突的可能性。只选择您可以确定永远不会用作原生属性的名称。例如scope,作为键是一个坏主意,因为它存在于某些 HTML 元素中......

现在来了.data()。其他答案似乎对它发誓,我避免它。与和expando 属性相关的内存泄漏.prop()通常属于过去,因此不再具有优势。但是您可以避免与 HTML 属性发生名称冲突。这是一个优势。但是你有很多缺点:

$(e).data('myKey')如果可用,则从属性中提取其未初始化的值,data-myKey在这些上运行 JSON.parse() 并有时返回该值或回退到属性的字符串值。一旦你设置$(e).data('myKey', myValue)了,你就失去了与data-myKey属性的关系,尽管如此,它仍然以其“旧”值存在,在 DOM 和 CSS 交互中显示。最重要的是,您使用的键名可能会受到名称修改的影响。即,如果您决定通过$(e).data()该对象中的键读取所有键值可能会有所不同。

由于这种不稳定的行为(将 expando 属性技术与data-*属性混合)和不一致的 get/set 设计,我总是避免.data().prop()使用 .-幸运的是,使用and很容易做到.attr()(使用data-*合规性键)。

如果你真的想用它.data()来避免与原生属性发生名称冲突,我的建议是:不要与data-*属性混合,将它们视为不同的东西,并避免与这些属性发生名称冲突。——这有意义吗?为了自动避免碰撞,您必须手动避免在其他地方发生碰撞。很棒的设计。

于 2020-04-06T16:10:16.747 回答