0

I accidentally typed the following code in JavaScript and it worked:

my_element.addEventListener("click", function() {
  alert("Hello world");  
})
#my_element {
  background: lightblue;
  width: 100px;
  height: 100px;
  position: absolute;
  top: 50px;
  left: 50px;
}
<div id="my_element">hello there</div>

I did not get the element using:

var element = document.getElementById("my_element");

I simply referenced the element like so and it worked!?!

my_element.addEventListener("click", function() {
  alert("Hello world");  
})

This works in Firefox and Chrome. I have not tested in other browsers. Is this well known? Is this fully supported in browsers?

I have always returned a reference to the HTML element. My shock is that I can simply type the ID of the element as if it was a global object!

1.21 gigawatts
  • 16,517
  • 32
  • 123
  • 231

1 Answers1

1

Yes, it's universally supported, and it's even now in the HTML5 specification. Automatic global variables are created for every element with an id (and many others with names).

I never rely on it, there are too many other things in the global namespace. But yes, it's defined behavior.


In a comment below you asked what happens when there's a conflict. More in my answer to another question, but there's an order to it. Automatic DOM globals are shadowed by declared global variables, in a couple of different ways. Here's an example:

// `example1` is a DOM automatic global
console.log(typeof example1);                                        // object
console.log("example1" in this);                                     // true
console.log(Object.prototype.hasOwnProperty.call(this, "example1")); // false

// We have both a DOM element with `example2` as its ID and also a
// `var`-declared global; the latter takes precedence
var example2;
console.log(typeof example2);                                        // undefined
console.log("example2" in this);                                     // true
console.log(Object.prototype.hasOwnProperty.call(this, "example2")); // true

// We have a DOM element with `example3` as its ID, a global object property
// with that name, and also a `let`-declared global variable; the latter wins
this.example3 = 42;
let example3;
console.log(typeof example3);                                        // undefined
console.log("example3" in this);                                     // true
console.log(Object.prototype.hasOwnProperty.call(this, "example3")); // true
.as-console-wrapper {
    max-height: 100% !important;
}
<div id="example1"></div>
<div id="example2"></div>
<div id="example3"></div>

In a further comment you asked:

What of the case of conflicts with existing global members? For example, if I name my element "window" or "document"? Will my element take precedents over the existing global object member?

No, window and document and others are own properties of the Window object, but the automatic DOM globals are on its prototype (on compliant browsers; not IE11 or IIRC Legacy Edge). So its own properties win. To get at the automatic DOM globals, you'd have to go to window's prototype:

// `window` here is still the global object
console.log(window === this);                              // true
var someVariableName;
console.log("someVariableName" in window);                 // true

// The automatic DOM global "window" is on its prototype:
console.log(Object.getPrototypeOf(window).window.tagName); // "DIV"
<div id="window"></div>

Of course, none of this is behavior you want to rely on. If you want to access a DOM element by its id, use getElementById (or querySelector or similar).

T.J. Crowder
  • 1,031,962
  • 187
  • 1,923
  • 1,875
  • Then the next question is do these automatic global members overwrite existing global properties or does it fail (silently or loudly) when naming conflicts occur? – 1.21 gigawatts Sep 23 '20 at 19:06
  • 1
    @1.21gigawatts - It *succeeds* silently, and not always in the way one expects. :-) The globals created for DOM elements are inherited properties of the global object (on modern browsers), so if you declare a variable with `var` at global scope (which creates an "own" property of the global object), that takes precedence over the automatic global. If you declare a variable with `let` or `const` at global scope, that's created on the inner global scope (which isn't connected to the global object), so it takes precedence over an automatic global or a global object property. – T.J. Crowder Sep 24 '20 at 06:18
  • 1
    @1.21gigawatts - More here: https://stackoverflow.com/questions/63178138/can-i-clarify-the-terminology-of-the-global-scope-global-objects-the-global-ob/63178497#63178497 – T.J. Crowder Sep 24 '20 at 06:19
  • 1
    (I've also added examples to the answer.) – T.J. Crowder Sep 24 '20 at 06:28
  • What of the case of conflicts with existing global members? For example, if I name my element "window" or "document"? Will my element take precedents over the existing global object member? – 1.21 gigawatts Sep 25 '20 at 22:29
  • 1
    @1.21gigawatts - Updated for that, too. (FWIW, it's "precedence" rather than "precedents.") – T.J. Crowder Sep 26 '20 at 08:24