Reputation: 47642
All browsers I've come to work with allow accessing an element with id="myDiv"
by simply writing:
myDiv
See here: http://jsfiddle.net/L91q54Lt/
Anyway, this method seems to be quite poorly documented, and in fact, the sources I come across don't even give it a mention and instead assume that one would use
document.getElementById("myDiv")
or maybe
document.querySelector("#myDiv")
to access a DOM element even when its ID is known in advance (i.e. not calculated at runtime). I can tell that the latter approaches have the advantage of keeping the code safe if someone inadvertedly attempts to redefine myDiv
in a wider scope (not such a brilliant idea though...), overwrites it with some different value and goes on without noticing the clash.
But other that that? Are there any concerns in using the short form above other than code design, or what else am I missing here?
Upvotes: 68
Views: 11511
Reputation: 467
As someone that has been developing Web-based applications for over 25 years, I can say with certainty that the only reason for this quirky behavior is backwards compatibility.
The method getElementById
wasn't even part of DOM Level 1. However, the earlier DOM Level 0 allowed direct access to most elements on the page:
https://docstore.mik.ua/orelly/webprog/dhtml/ch02_04.htm
As you can see, browsers like Netscape 6 and MSIE 5 continued to support the old convention, even after getElementById
was adopted as a "standard"
The earliest DHTML capable browsers like Netscape Navigator and MSIE frequently pushed their own DOM specs into the marketplace. So you ended up with a lot of bad design decisions which ultimately became standardized by virtue of "that's how it was done before".
https://www.quirksmode.org/js/dom0.html
For reasons of backward compatibility the more advanced browsers, even those who support the Level 1 DOM, still also support the old, faithful Level 0 DOM. Not supporting it would mean that the most common scripts suddenly wouldn't work any more. So even though the Level 0 DOM doesn't entirely fit into the new DOM concepts, browsers will continue to support it.
When Netscape introduced Level 0 DOM, it was likely assumed that Web-based applications would never amount to more than auto-filling a few form fields and moving some images around the screen. So there was no concern about polluting the global window object with a handful of element IDs.
Obviously that solution didn't scale well at all. But we're stuck with this archaic Level 0 DOM convention just so as not to break legacy Javascript code.
Upvotes: 2
Reputation: 21044
In my case I had an iframe inside my page. I was confused by id
attribute vs name
attribute, both of which affected a variable named inner_iframe
, accessible from window
!
If I used only the id attribute, like id="inner_iframe"
, window.inner_iframe
is a HTMLIFrameElement
. Properties include inner_iframe.contentDocument
and inner_iframe.contentWindow
as described here*
window
because of the reason quoted by @joew in the accepted answer:
HTML elements that have an id content attribute whose value is name
If I used only the name attribute, like name="inner_iframe"
then window.inner_iframe
is a "frame", aka a "window object". contentWindow
, therefore the name-attribute inner_iframe does not have properties contentDocument
or contentWindow
.
inner_iframe
variable appears on window
because of the reason quoted by @joew in the accepted answer
child browsing contexts of the active document whose name is name
name
and id
attributes, and I gave both attributes the same value name="inner_iframe" id="inner-iframe"
; the name
attribute trumped/clobbered the id
attribute; I was left with the "window object", not the HTMLIFrameElement
!So my point is to be careful about ambiguity; the conflict between name
and id
attributes on the same object with two different APIs: is just a specific case where implicit behavior and attachment to a window variable may confuse you.
*(and only if the <script>
was loaded after/beneath the <iframe>
in the HTML, or the <script>
waited until window.onload
before trying to access by id attribute)
**this "frame" vs DOM Element distinction is described in Mozilla documentation as:
Each item in the window.frames pseudo-array represents the window object corresponding to the given 's or 's content, not the (i)frame DOM element (i.e., window.frames[0] is the same thing as document.getElementsByTagName("iframe")[0].contentWindow).
Upvotes: 2
Reputation: 23863
There are a few reasons:
You don't want your code and your markup that coupled.
By using a specific call to access a div, you don't have to worry about the global space being corrupted. Add a library that declares myDiv
in global space and you're in a world of pain that will be hard to fix.
You can access elements, by ID, that aren't part of the DOM
They can be in a fragment, a frame, or an element that has been detached and not re-attached to the DOM yet.
EDIT: Example of accessing a non-attached elements by ID
var frag = document.createDocumentFragment();
var span = document.createElement("span");
span.id = "span-test";
frag.appendChild(span);
var span2 = frag.getElementById("span-test");
alert(span === span2);
Upvotes: 17
Reputation: 30330
Anyway, this method seems to be quite poorly documented, and In fact, the sources I come across don't even give it a mention [...]
Reliance on implicitly-declared global variables aside, the lack of documentation is a great reason not to use it.
The apparent promotion of id
values into global variables isn't standards compliant (the HTML5 spec for the ID attribute doesn't mention it) and, therefore, you shouldn't assume future browsers will implement it.
EDIT: It turns out this behaviour is standards compliant - In HTML5, window
should support property access to "Named Elements":
Named objects with the name name, for the purposes of the above algorithm, are those that are either:
- child browsing contexts of the active document whose name is name,
- a, applet, area, embed, form, frameset, img, or object elements that have a name content attribute whose value is name, or
- HTML elements that have an id content attribute whose value is name.
Source: HTML 5 spec, 'Named access on window object", emphasis mine.
Based on this, standards compliance is not a reason to avoid this pattern. However, the spec itself advises against its use:
As a general rule, relying on this will lead to brittle code. Which IDs end up mapping to this API can vary over time, as new features are added to the Web platform, for example. Instead of this, use
document.getElementById()
ordocument.querySelector()
.
Upvotes: 53
Reputation: 98786
Great question. As Einstein probably didn’t say, things should be as simple as possible, and no simpler.
the latter approaches have the advantage of keeping the code safe if someone inadvertedly attempts to redefine myDiv in a wider scope (not such a brilliant idea though...), overwrites it with some different value and goes on without noticing the clash
That’s the main reason why this is a bad idea, and it’s quite enough. Global variables aren’t safe to rely on. They can be overwritten at any time, by any script that ends up running on the page.
In addition to that, just typing in myDiv
isn’t a “short form” of document.getElementById()
. It’s a reference to a global variable.document.getElementById()
will happily return null
if the element doesn’t exist, whilst attempting to access a non-existent global variable will throw a reference error, so you’d need to wrap your references to the global in a try/catch block to be safe.
This is one reason why jQuery is so popular: if you do $("#myDiv").remove()
, and there is no element with an id of myDiv
, no error will be thrown — the code will just silently do nothing, which is often exactly what you want when doing DOM manipulation.
Upvotes: 21