我正在使用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); });
忽略我的示例代码的任何其他缺点,是否有充分的理由说明为什么选择一种方法来存储属性?
答案 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属性.attr('data-*')
.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-*
属性混用,将它们视为另一回事,并避免与这些属性发生名称冲突。那有意义吗?为了自动避免冲突,您必须手动避免其他地方发生冲突。很棒的设计。