The global scope polluter has pretty bad performance and interop surprises, you shouldn't depend on it and instead use getElementById even if it's a bit more verbose.
It uses a property interceptor which is fairly slow in v8:
Is there a reason to not use querySelector, since it’s a lot more flexible? One reason jQuery became so popular is because the DOM was painful to use. Things like querySelector fix that.
I'm surprised to find that this trick still works even in the new backwards-incompatible JavaScript Modules (using <script type="module">), which enables "strict" mode and a number of other strictness improvements by default.
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.
This seems like a missed opportunity. JavaScript Modules should have been required to "import {window} from 'dom'" or something, clearing out its global namespace.
There is some effort to standardize something along these lines. Well, some things which combined would achieve this. It’s too late to bake it into ESM, but I believe it’ll be possible with ShadowRealms[1] and/or SES[2], and Built-in Modules (JS STL)[3].
I don't think this article is complete. It mentions no pollution, which is true of window and most HTML elements, but not always. Check this out, you can set an img name to getElementById and now document.getElementById is the image element!
<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
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.
This is one of those things that pops up every year or two years. Unfortunately, the person writing about the new discovered weird trick almost always fails to precede the article with a big, red, bold "Please don't ever do this".
Yeah, HTML5 explicitly documented the compatible behaviors between browsers to reach uniformity, which meant standardizing a lot of weird stuff instead of trying to fix it.
Yep, same here. The only time I use this bit of knowledge nowadays is in the console. If I see a tag has an ID, I save myself a few characters by just referring to it as a variable since I know it's already there anyways.
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.
This always reminded me of PHP’s infamous register_globals. For those unfamiliar, anything in the ‘$_REQUEST’ array (which itself comprises of $_POST, $_GET, and $_COOKIE merged together) is added to the global scope. So if you made a request to index.php?username=root, $username would contain “root” unless it was explicitly initialized it before it was used.
iirc this doesn't work in Firefox? or at least it doesn't work the same way as in Chrome. I developed a tiny home-cooked app[0] that depended on this behavior using desktop Chrome which then broke when I tried to use it on mobile Firefox. I then switched it to using
document.getElementById
like I should have and everything worked fine. Like others in this thread, I recommend not relying on this behavior.
You can make this yourself with Proxy. I get a lot of mileage out of this:
// 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!`)
});
The Netscape of the 90s wasn't interested in making features ‘safe’. They were about throwing out features as quickly as possible to see what would stick.
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
I saw this "shortcut" used in code snippets, on online JS/CSS/HTML editors like JSFiddle. It did not even occur to me this was part of JS spec, I thought the editor was generating code behind my back!
If you read the article and the spec, you'll see that any explicitly created variables will always take precedence over automatic IDs, so any globals will always override these IDs.
You shouldn't be using IDs anyways. They are just bad for a lot of reasons. You can only have one on a page and it reduces your reusability. Use classes instead.
For me, the disadvantage above any listed on the blog is that if I saw this global variable referenced in some code (especially old code, where some parts might be defunct), I would have absolutely no idea where it came from, and I bet a lot of others would struggle too.
This was mostly useful back in the days when we had to manually query dom during development and debugging. I've seen some pretty horrible things but never have I seen this in a codebase, not even in a commit
I remember using it on the first Javascript I ever used around 20 years ago. I naively assumed that the DOM was like state in a more procedural language and this variable trick played into that.
*rigmarole, if we're being pedantic, but I suspect the contemporary spelling "rigamarole" is gaining on the proper spelling, and that's one of the wonderful/terrible things about the English language.
I don't want to sound like I have an axe to grind (but I do), but this is the kind of feature/wart that shows the age of the HTML/CSS/JS stack.
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?).
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 :)
I find it pretty funny that we humans have invented all these transpilers and bundlers, invested probably billions of dollars in JITs, just to keep writing JS
esprehn|3 years ago
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!
toddmorey|3 years ago
goatlover|3 years ago
dfabulich|3 years ago
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.
This seems like a missed opportunity. JavaScript Modules should have been required to "import {window} from 'dom'" or something, clearing out its global namespace.eyelidlessness|3 years ago
1: https://github.com/tc39/proposal-shadowrealm
2: https://github.com/tc39/proposal-ses
3: https://github.com/tc39/proposal-built-in-modules
stonewareslord|3 years ago
Here's a minimal example (https://jsfiddle.net/wc5dn9x2/):
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/
jefftk|3 years ago
dwild|3 years ago
It's weirdly not that discussed on the web, most probably because it require a pretty specific situation.
FrontAid|3 years ago
esprehn|3 years ago
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.
efdee|3 years ago
simlevesque|3 years ago
I must have never used "name" as a name for a global variable or just for ones that were strings.
genezeta|3 years ago
svnpenn|3 years ago
https://wikipedia.org/wiki/Wikipedia:Chesterton's_fence
LelouBil|3 years ago
mmastrac|3 years ago
It's great for hacking a tiny script together, however.
esprehn|3 years ago
See for example this thread where Mozilla tried to not do this: https://bugzilla.mozilla.org/show_bug.cgi?id=622491
russellbeattie|3 years ago
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.
unknown|3 years ago
[deleted]
samtho|3 years ago
twicetwice|3 years ago
[0]: https://www.robinsloan.com/notes/home-cooked-app/
shadowgovt|3 years ago
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).
kiawe_fire|3 years ago
Something like “window.elements.myDiv”? I wonder why the decision to go straight to the root.
dphnx|3 years ago
[1]: https://developer.mozilla.org/en-US/docs/Web/API/Document/al...
akira2501|3 years ago
bobince|3 years ago
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
bjkchoy|3 years ago
seba_dos1|3 years ago
It has nothing to do with JS spec; it's part of the DOM as defined by the HTML spec.
angelmm|3 years ago
mmastrac|3 years ago
[1] https://developer.mozilla.org/en-US/docs/Glossary/IIFE
Slackwise|3 years ago
bhhaskin|3 years ago
grenoire|3 years ago
unknown|3 years ago
[deleted]
eithed|3 years ago
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
mmazzarolo|3 years ago
roberttod|3 years ago
croes|3 years ago
>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?
beebeepka|3 years ago
7952|3 years ago
bsimpson|3 years ago
I wouldn't use it in production, but it's handy for banging together a proof-of-concept.
monkpit|3 years ago
SpaceL10n|3 years ago
codedokode|3 years ago
graderjs|3 years ago
tambourine_man|3 years ago
Should read “rigamarole”
thunderbong|3 years ago
Today I learned, it's both!
https://en.wiktionary.org/wiki/rigmarole
spdustin|3 years ago
pkrumins|3 years ago
mikessoft_gmail|3 years ago
[deleted]
debacle|3 years ago
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?).
eptcyka|3 years ago
WallyFunk|3 years ago
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 :)
doliveira|3 years ago
tfsh|3 years ago
goatlover|3 years ago