16

What is the difference between using document.head and using document.getElementsByTagName("head")[0]? Tests I ran showed that they both take about a millisecond.

I have also seen

document.head||document.getElementsByTagName("head")[0];

which would have led me to believe that document.head is faster and the other is more more compatible, except that the tests I did disproved this.

And if one is more compatible, why use the other as well?

Update: My tests were wrong, as some have pointed out.

Brian McCutchon
  • 8,354
  • 3
  • 33
  • 45
  • You can also do `document.querySelector("head")`. It's just a matter of choice. – Derek 朕會功夫 Apr 25 '13 at 01:09
  • It pretty much can't become any faster than having a direct reference. So `document.head` should be faster by a magnitude, see http://jsperf.com/document-head-vs-getelementsbytagname – jAndy Apr 25 '13 at 01:15
  • 2019 update: please stop adding unnecessary `|| document.getElementsByTagName("head")[0]`, IE8 is *long* dead. – Chris Morgan Feb 05 '19 at 06:27

4 Answers4

13

Using the || operator like that is a form of feature detection. When used, if the first value is undefined it sends back the latter value.

So for

document.head || document.getElementsByTagName("head")[0];

the reason is that if document.head is not supported at least the right value is returned.

As for your speed test, a millisecond is a long time. I doubt it really took that long. In fact, I made a jsPerf for this. It shows that the getElementsByTagName function is roughly 80% slower.

Travis J
  • 81,153
  • 41
  • 202
  • 273
5

According to MDN, document.head only gained support in IE 9, so using the other method as a fallback protects you from browser incompatibilities

Alex.Bullard
  • 5,533
  • 2
  • 25
  • 32
  • But if `document.getElementsByTagName("head")[0]` is more compatible, why use `document.head` at all? – Brian McCutchon Apr 25 '13 at 01:08
  • @Sortofabeginner Because it's shorter, and easier to read. There are multiple ways to query the DOM. In some cases, the *other way* may become deprecated. I don't suspect that will happen in this case though. – Sampson Apr 25 '13 at 01:09
2

This is more of a convenience matter than a performance one (though document.head should have a negligible benefit). Use which ever you like, or, use one as a fallback to the other (as your example code does). Having the fallback is wise, since document.head is not support in IE 6-8.

It's not likely that getElementsByTagName will soon be deprecated, so this isn't a great example of when it's good to provide a fallback. You could safely use the more verbose route on its own and enjoy support on into the future.

Better examples of these types of things would be events, and how they're passed around in modern browsers, compared to older browsers. It is not uncommon to see something like this:

function callback (event) {
    var id = (event || window.event).target.id;
}

In this case though, the window.event portion is necessary for legacy support. If the event object is undefined, we assume the event is a member on the window object. As browsers mature, window.event ceases to be a thing, and these tests unanimously return event.target.id instead.

Again, your case is a bit different as getElementsByTagName will likely never be deprecated or vanish as window.event did.

Sampson
  • 265,109
  • 74
  • 539
  • 565
  • I don't think a ~83% performance penalty is *just* a matter of convenience. http://jsperf.com/document-head-vs-getelementsbytagname – jAndy Apr 25 '13 at 01:16
  • 2
    @jAndy ~83% on this scale is negligible. This is not the type of preoptimization web developers need to be worrying about, generally speaking. – Sampson Apr 25 '13 at 01:17
  • 2
    I disagree. I'd expect to query for DOM elements as fast as anyhow possible, since this kind of operation might happen thousands of times. – jAndy Apr 25 '13 at 01:20
  • 2
    @jAndy If your page is querying for the `head` element *thousands of times*, you have no business being in this industry ;) I think we can both agree that cached references to DOM nodes is better than repeatedly looking them up. But the speed different for getting the `head` element is negligible. – Sampson Apr 25 '13 at 01:23
  • well, I was talking about DOM queries, but I guess you just wanna tease here. I just disagree that the performance penalty of accessing a property + executing a function + accessing the resulting HTMLCollection is neglible in comparison to a direct reference. This spreads a very wrong message. – jAndy Apr 25 '13 at 01:24
  • @jAndy We're talking about querying for the `head` element; not *elements in general*. Clearly cached references are quicker than making repeated trips to the DOM. Please don't mistake my position here, I'm on your side 99% of the time. – Sampson Apr 25 '13 at 01:25
  • I know, but still, there are other shortcuts like `document.body`, `document.images`, `document.links` etc. which are about the same topic. I wouldn't dare to recommend to use `getElementsByTagName()`, I'd always state to use those references, not just for convenience, every day all day. – jAndy Apr 25 '13 at 01:27
  • @jAndy I would agree that `document.images` is better than crawling the DOM for *multiple tags*. But that's apples and oranges; we're talking about `document.head`, which craws the DOM (very briefly since it's at the top) for one element. – Sampson Apr 25 '13 at 01:31
  • well, I guess we look at things differently, but fair enough. – jAndy Apr 25 '13 at 01:32
  • @jAndy Not too much differently; again, multiple trips, or single trips for multiple elements, always take the most performant route. In this case, `document.head` is better, but isn't more appealing because of a major performance boost (though it technically provides a boost). – Sampson Apr 25 '13 at 01:34
1

Just convenience because you are only supposed to have one per page. Just like there is a direct shortcut to document.body, although document.body is standard and you wouldn't need the fallback.

document.body || document.getElementsByTagName("body")[0]

I wouldn't use document.head unless you only support IE9+. Until then, I would stick to document.getElementsByTagName("head")[0]

If you want a version that you don't have to change as time goes by, you can do the following at the top of your script

document.head = document.head || document.getElementsByTagName("head")[0];

That way you can just change that one place when you drop support for IE8 (or may even leave it there since it doesn't hurt, but it will be dead code). The above code would also make sure you only query the DOM once

Ruan Mendes
  • 90,375
  • 31
  • 153
  • 217
  • You put body instead of head. – Brian McCutchon Apr 25 '13 at 01:15
  • 1
    You only fixed it in one location - there are several other instances. – Brian McCutchon Apr 25 '13 at 01:18
  • @sortofabeginner the first one is intentional to show the same pattern can be used for document.body – Ruan Mendes Apr 25 '13 at 03:30
  • Fair enough. I wonder if `document.head||(document.head=document.getElementsByTagName("head")[0]);`wouldn`t be slightly faster? – Brian McCutchon Apr 25 '13 at 23:15
  • @Sortofabeginner faster than what? Why would that be any faster than `document.head = document.head || document.getElementsByTagName("head")[0];` if you follow my suggestion it only happens once anyway, I think you're splitting hairs, if you have a real performance question, ask a new one – Ruan Mendes Apr 25 '13 at 23:43