-->

Storing data to DOM - Element value vs data attrib

2020-08-27 01:32发布

问题:

To store values in a DOM element, we can do it through data attribute

$("#abc").data("item", 1), to retrieve do $("#abc").data("item")

But today I learned that we can do it this way also:

$("#abc")[0].item = 1, to retrive do $("#abc)[0].item

What are the differences between them? Which one is better? Which one gets a wider compatibility?

回答1:

.data() exists for a couple reasons:

  1. Some (mostly older) browsers had memory leak issues if you put a JS object into a property on a DOM object. This created a reference between the DOM and JS world (which have separate garbage collectors) which caused problems and could result in memory leaks. Keep references entirely in the JS world by using .data() instead of a DOM property solved that issue. I don't honestly know how much of an issue this still is in modern browsers. Hard to test, easier to just use the known-safe approach.

  2. Historically, some host objects did not support arbitrary property addition with direct property syntax such as obj.prop = 1;. .data() made it so you could associate data with any object regardless of whether it had the ability to handle any arbitrary property.

  3. Name collisions. .data() creates one and only one custom property on a DOM object which is just an id value (a string). You are then free to use any keys you want with .data() with zero worry about conflicting with a pre-existing property name on a DOM object. .data() is essentially it's own name space for custom properties.

  4. Reading HTML5 "data-xxx" attributes. When you read a .data("xxx") property that has not yet been written to the actual jQuery data store, jQuery will read a "data-xxx" attribute on the DOM object. If it finds that attribute, it returns that value and actually coerces its type too so that "false" gets turned into the Javascript false. If you then write .data("xxx", "foo"), the value is not overwritten onto the DOM object, but is written to the jQuery storage and from then on all future reads writes are from the jQuery .data() store. One reason this is useful is that custom attributes (which are different than custom properties) can only be strings, but .data("xxx", yyy) can write and store any JS data type.

So, if you want to use a known-safe method that is not prone to memory leaks, even in older browsers, use .data() rather than making your own custom property on a DOM object.

I suspect it's possible that at some future time, browsers will be considered safe enough that you can store JS object references in custom DOM properties and not have to worry about memory leaks at which time there may be less reasons to use something like .data() - though issue #3 above will still exist.


There are some disadvantages to using .data().

  1. If you store meaningful amounts of data in .data() and then you remove the corresponding DOM object without using jQuery's methods to remove it (such as you use .removeChild() directly or you just set .innerHTML on a parent), the data stored in the .data() store will be orphaned and never cleaned up because jQuery will not know the corresponding DOM object has been removed. This will result in some data in your javascript being kept in the data structure that you won't ever be using. While this isn't technically a leak (as the data is still there for use), it has much the same effect of wasting some memory. If you use .data(), you should only use jQuery methods for removing or replacing DOM objects because they prevent the wasted memory.

  2. Because of the above issue, when you are using jQuery's methods that can result in the removal of DOM objects, jQuery has to do extra work to make sure .data() is cleaned up when using its own methods. This can slow down the performance of .html("xxx"), .remove(), etc...