3

I often read it's bad practice, because it's hard to maintain, but doing:

document.getElementsByTagName("h1")[0].foo = {"key":"value"};

compared to using the recommended jQuery alterantive:

$.data($(document.getElementsByTagName("h1")[0]), "foo", {"key":"value"});

is just so much faster: jsperf

Both data and my hack are not visible in a debugger like Firebug, so from a "visibility" point of view there is no difference in using either one.

Question:
Why is bad practice to store information directly on the element?

Brian Tompsett - 汤莱恩
  • 5,753
  • 72
  • 57
  • 129
frequent
  • 27,643
  • 59
  • 181
  • 333
  • If neither is visisible you haven't looked closely enough. – Bergi Nov 14 '13 at 10:48
  • wouldn't `$('h1').eq(0).data('foo', {"key":"value"})` be a better idea ? – adeneo Nov 14 '13 at 10:49
  • looking closely... still see nothing :-) How do you see data() being set on an HTML element? – frequent Nov 14 '13 at 10:49
  • By checking the elements properties in the console. – adeneo Nov 14 '13 at 10:49
  • @adeneo: check the jsperf. – frequent Nov 14 '13 at 10:49
  • @frequent: It does set a `jQuery` property on the element. – Bergi Nov 14 '13 at 10:50
  • @Bergi: (looking again :-) – frequent Nov 14 '13 at 10:50
  • @Bergi: ok, looking real close in Firebug, if I console the element in a jQuery selector, it does have a little envelope, which when clicked shows the baggage. But still, is this the only reason to not use? – frequent Nov 14 '13 at 10:52
  • 1
    The advantage of using `data()` is that it gets populated if you use the `data-*` attributes in your HTML – sdabet Nov 14 '13 at 10:52
  • 1
    @frequent - setting a property directly is much faster, no suprise there, but setting it with data() is safe and avoids circular references and DOM errors, and that's mostly why it's slower. – adeneo Nov 14 '13 at 10:52
  • 1
    @RohanKumar - Doesn't really matter, jQuery creates an object called $.cache, and each element that has data() attached only gets a property with an ID, this ID is then used as a key in the $.cache object to look up whatever data is stored, so the data is never stored on the element itself, it's in a seperate object thus avoiding memory leaks and circular references etc. To work with HTML5 data attributes, .data() always checks getAttribute('data-') first to see if any data is attached directly to the element in the markup. – adeneo Nov 14 '13 at 10:58
  • Maybe have a look at [Should I use setAttribute to add properties to an element?](http://stackoverflow.com/questions/10833853/should-i-use-setattribute-to-add-properties-to-an-element) – Bergi Nov 14 '13 at 11:03
  • I'm pretty sure in your example it's trivial or even better to use a native function, but the value of using jquery to set it is all the other benefits of the framework, like more robust selectors and the ability to easily chain the `data()` function to 7 other methods. Read the countless blog entries from the last year discussing jquery vs native js to get all the pros and cons. – Anthony Nov 14 '13 at 11:06

2 Answers2

5

There are a couple reason why custom properties such as .foo are not advisable:

  1. In some browsers, depending upon what you assign to the custom properties, you can end up with circular references between DOM and JS which can lead to memory leaks in some circumstances.

  2. The element property namespace is reserved for use by the browser and for future properties. That's why the HTML5 spec even suggests that all custom attributes be prefixed with the data- prefix to put them all in that one name. So, if you start randomly adding properties to your DOM elements, you are likely to conflict with something now or in the future.

jQuery's .data() creates a javscript object and stores all the data elements created with .data() in javascript. It used one custom properties as an index into the .data() world so that it can find the right items that belong to a particular DOM element. It has no chance of a DOM <--> JS circular reference and your keys used with .data() will never conflict with DOM property names.


FYI, the more common way to use .data() is via method on a jQuery object such as:

$("h1").eq(0).data("foo", {"key":"value"})

It is not uncommon that native methods are faster than jQuery alternatives because jQuery does more in order to offer its extended feature set and cross browser compatibility, though jQuery is generally for it's speed to not be noticed. You would generally use jQuery to help with cross browser compatibility and to use it's features to speed up your development effort. Performance optimizations are generally done much later only when you've isolated and profiled a particular performance issue and there are times when some jQuery can be replaced with native code to speed up a particular operation.

jfriend00
  • 683,504
  • 96
  • 985
  • 979
1

If it is for the single element then an id selector would be best, I think.

You can use :first selector like,

$.data($("h1:first"), "foo", {"key":"value"});

And using an data-* attribute you can set multiple attributes in one single data rather than using multiple-attributes (which may not works in some browsers).

Rohan Kumar
  • 40,431
  • 11
  • 76
  • 106