It uses a property interceptor which is fairly slow in v8:
https://source.chromium.org/chromium/chromium/src/+/main:out...
to call this mess of security checks:
https://source.chromium.org/chromium/chromium/src/+/main:thi...
which has this interop surprise:
https://source.chromium.org/chromium/chromium/src/+/main:thi...
which in the end scans the document one element at a time looking for a match here:
https://source.chromium.org/chromium/chromium/src/+/main:thi...
In contrast getElementById is just a HashMap lookup, only does scanning if there's duplicates for that id, and never surprisingly returns a list!
getElement is slightly faster, but not by enough to care IIRC so I use querySelector for consistency and it's flexibility.
> One reason jQuery became so popular is because the DOM was painful
I would say that is the key reason, with everything else being collateral benefits. Assuming you combine element selection, dealing with legacy incompatibilities, and function chaining to reduce boilerplate code, under the same banner of "making the DOM less painful".
https://jsbench.github.io/#b39045cacae8d8c4a3ec044e538533dc
ProTip: Without numbers performance opinions are wrong by several orders of magnitude 80% of the time.
I believe it works because the global object ("globalThis") is the Window in either case; this is why JavaScript Modules can refer to "window" in the global scope without explicitly importing it.
<!DOCTYPE html><body>
<div id="cool">cool</div>
<script>
console.log(this); // Window
console.log(globalThis); // Window
console.log("script", cool.innerHTML); // script cool
</script>
<script type="module">
console.log(this); // undefined
console.log(globalThis); // Window
console.log("module", cool.innerHTML); // module cool
</script>
</body></html>
This seems like a missed opportunity. JavaScript Modules should have been required to "import {window} from 'dom'" or something, clearing out its global namespace.1: https://github.com/tc39/proposal-shadowrealm
Here's a minimal example (https://jsfiddle.net/wc5dn9x2/):
<img id="asdf" name="getElementById" />
<script>
// The img object
console.log(document.getElementById);
// TypeError: document.getElementById is not a function :D
console.log(document.getElementById('asdf'));
</script>
I tried poking around for security vulnerabilities with this but couldn't find any :(It seems that the names overwrite properties on document with themselves only for these elements: embed form iframe img object
Edit: Here's how I found this: https://jsfiddle.net/wc5dn9x2/1/
It's weirdly not that discussed on the web, most probably because it require a pretty specific situation.
var name = true;
typeof name; // "string", not "boolean"
Luckily, this is not true within ES modules which you probably use most of the time anymway. <script>
var _value = "test value";
Object.defineProperty(window, "testName", {
get: () => _value,
set: (value) => { _value = String(value) },
});
</script>
<script>
var testName = {};
// prints [object Object] string
console.log(testName, typeof testName);
var name = {};
// prints [object Object] string
console.log(name, typeof name);
</script>
the `var` doesn't create a new property since the getter and setter already exist.Other properties have the same behavior, for example `status`.
Note: there's also LegacyUnforgeable which has similar behavior: https://webidl.spec.whatwg.org/#LegacyUnforgeable
Even if you're not using modules, using an IIFE avoids all this by making your variables local instead of having them define/update properties on the global.
name = {first: "Jane", last: "Doe"}
isn't obviously unreasonable. Which actually sets name to the string "[object Object]".I must have never used "name" as a name for a global variable or just for ones that were strings.
It's great for hacking a tiny script together, however.
See for example this thread where Mozilla tried to not do this: https://bugzilla.mozilla.org/show_bug.cgi?id=622491
IDs were the only way to get a reference to an element early on if I'm remembering correctly. Or maybe the DOM API just wasn't well known. All the examples and docs just used IDs, that I can remember for sure.
document.getElementById
like I should have and everything worked fine. Like others in this thread, I recommend not relying on this behavior.In 2022, that alone is enough to wipe it from my toolbox as a web developer. Ain't nobody got time for that.
(... there are lots of other reasons it'd be bad practice to rely on this as well, although it's nice for debugging when available).
Something like “window.elements.myDiv”? I wonder why the decision to go straight to the root.
<div id="foo"></div>
<script>
const { foo } = document.all
// do something with foo
</script>
Don't use it though, it's deprecated as well[1].[1]: https://developer.mozilla.org/en-US/docs/Web/API/Document/al...
// proxy to simplify loading and caching of getElementById calls
const $id = new Proxy({}, {
// get element from cache, or from DOM
get: (tgt, k, r) => (tgt[k] || ((r = document.getElementById(k)) && (tgt[k] = r))),
// prevent overwriting
set: () => $throw(`Attempt to overwrite id cache key!`)
});
Now if you have <div id="something></div>
You can just do $id.something.innerHTML = 'inside!';The simplest possible syntax is to make named elements available globally, and if that clashes with future additions to the DOM API then well that's a problem for some future idiots to worry about.
as a strategy it worked pretty well, unfortunately
It has nothing to do with JS spec; it's part of the DOM as defined by the HTML spec.
{
let foo = 1
};
// foo is undefined here[1] https://css-tricks.com/named-element-ids-can-be-referenced-a...
This doesn't seem to be true as shown within this fiddle: https://jsfiddle.net/L785cpdo/1/
Bear in mind that only undefined elements will be declared this way
>So, if a DOM element has an id that is already defined as a global, it won’t override the existing one.
So, if a global has name of the id of a DOM element, it won’t override the existing one?
Wouldn't it be clearer to say globals always before DOM ids?
I wouldn't use it in production, but it's handy for banging together a proof-of-concept.
Should read “rigamarole”
Today I learned, it's both!
The whole thing is ripe for a redo. I know they get a lot of hate, but of all the big players in this space I think FB is the best equipped to do this in a way that doesn't ruin everything. I just wonder if they have an incentive (maybe trying to break the Google/MS hegemony on search?).
If FB could launch a browser on iOS that was in their walled garden, not only would it quickly receive wide adoption but it might become people's primary browser.
Not that I necessarily think that's a good thing, mind you.
Web developers have worked around quirks for as long as I can remember. The stack has many warts, but we learn to adapt to them. Like 90% of a web developer's job is working around gotchas, and will continue that way. A 'redo' might not be needed. Developers need something to moan about and need something to keep them employed :)
"If FB decided to try and break into search, then they might decide to attack the HTML/CSS/JS stack."
Not the other way around.