使用jQuery的数据存储区与expando属性

时间:2009-07-21 16:11:41

标签: javascript jquery

我正在使用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 个答案:

答案 0 :(得分:21)

使用$.data可以防止内存泄漏。

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

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

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

答案 1 :(得分:12)

如果您正在创作插件,则应使用$.data。如果您需要经常存储属性而很少需要查询DOM,请使用$.data

<击> 对我所有的客户端应用程序说,我倾向于在DOM元素本身上存储自定义DOM属性,以便稍后使用属性[]选择器查询它们:

var domElement = $('.interesting-line[lineNumber=' + lineNumber + ']').get(0);

这比在每个项目上迭代调用.data()的包装集更具可读性。我经常与另一个在DOM元素上运行的第三方库进行交互,因此通过这种机制可以快速方便地访问DOM元素,从而保持代码的可读性。

这就像存储将lineNumbers映射到元素的查找表一样容易,但是,比较时,expando属性技术更不容易泄漏内存,因为你没有存储引用稍后需要清理的DOM元素。

5年后更新 在收到[当之无愧的] downvote之后阅读本文:请忽略上面的标记文本。 jQuery基于expando属性集查询DOM,并且暂时没有这样做。所以使用$.data。当没有实用的方法时,没有理由污染DOM。

答案 2 :(得分:2)

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

答案 3 :(得分: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()之类的东西,或者想从包含数据的字符串构造代码段时。如果要使用elem[data-myKey]之类的CSS选择器,则同样适用。缺点:您只能存储字符串。

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

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

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

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

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

如果您真的想使用.data()来避免与本机属性发生名称冲突,我的建议是:不要与data-*属性混用,将它们视为另一回事,并避免与这些属性发生名称冲突。那有意义吗?为了自动避免冲突,您必须手动避免其他地方发生冲突。很棒的设计。