9 ms·
Named element IDs can be referenced as JavaScript globals
- mmastrac 4y agoThis has been a thing since the 90s. I really wish we'd done away with it for any document that specifies itself as HTML5. It's great for hacking a tiny script together, however.
- deleted 4y ago[deleted]
- esprehn 4y agoYeah, 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. See for example this thread where Mozilla tried to not do this: https://bugzilla.mozilla.org/show_bug.cgi?id=622491 https://bugzilla.mozilla.org/show_bug.cgi?id=622491
- russellbeattie 4y agoYep, 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.
- kiawe_fire 4y agoSeems like something that could have been made safer just by name spacing it a bit better. Something like “window.elements.myDiv”? I wonder why the decision to go straight to the root.
- dphnx 4y ago`document.all` can be used in this way: <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/all https://developer.mozilla.org/en-US/docs/Web/API/Document/al...
- bobince 4y agoThe 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
- WorldMaker 4y agoAs the article points out, this initiative was an 90s IE one and the Gecko team (Firefox, post-Netscape) were against it.
- akira2501 4y agoYou 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!`) }); Now if you have <div id="something></div> You can just do $id.something.innerHTML = 'inside!';
- shadowgovt 4y ago> It is implemented differently in browsers 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).
- bsimpson 4y agoI've definitely used this shortcut to make CodePens less verbose… I wouldn't use it in production, but it's handy for banging together a proof-of-concept.
- monkpit 4y agoIt hurts
- SpaceL10n 4y agoI think it would hurt less with TypeScript global types. Just need to know what IDs you'd expect to find in the DOM.
- err4nt 4y agothe ID's in DOM will never conflict or cause an issue with your own JS code. You can't reliably use 'named access on the window object' (the name of this feature) because of this, so it's never a problem, and also largely useless.
- grenoire 4y agoI discovered this the hard way and I am still really torn. The entire window global object is just a minefield.
- angelmm 4y agoNow I'm worried of using IDs and finding issues with globals in JavaScript. Seems to be a curious issue to be debugged.
- mmastrac 4y agoAvoid globals at all costs - use IIFE [1] instead, wrapping your function in parenthesis and invoking it right away. [1] https://developer.mozilla.org/en-US/docs/Glossary/IIFE https://developer.mozilla.org/en-US/docs/Glossary/IIFE
- an1sotropy 4y agoWhen, today, does it make more sense to organize things around IIFEs and not ES6 modules?
- recursive 4y agoIf you have access to `let`, you can just put `let` declarations into a block. No need for a function to establish scope.
- throw_m239339 4y ago{ let foo = 1 }; // foo is undefined here
- jbverschoor 4y agoAnd then get coworkers to remove it because they don’t understand that you can create scopes like that
- WorldMaker 4y agoIt's 2022, you can use ES2015 modules now. We can leave IIFE to the dustbin of the past.
- Slackwise 4y agoIf 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.
- genezeta 4y agoThis 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".
- svnpenn 4y agoand then someone always follows up with "Please don't ever do this", without explaining WHY you should never do this: https://wikipedia.org/wiki/Wikipedia:Chesterton's_fence https://wikipedia.org/wiki/Wikipedia:Chesterton's_fence
- genezeta 4y agoIt's has been explained enough times. It's just that looking things up for yourself seems to have gone out of fashion.
- scratcheee 4y ago>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" > It's has been explained enough times. It's just that looking things up for yourself seems to have gone out of fashion. It appears you've countered your own complaint.
- spookthesunset 4y agoThat doesn’t help people who stumble upon this when searching for the problem. All the “look it up” response does is make sure the search results are a bunch of content saying “look it up”, which isn’t really that helpful.
- nkozyra 4y agoIt is explained fairly early in the article. This used to be done quite a lot in the early JS days when scope was kind of thrown out the window (no pun) and you just did whatever dirty thing you needed to in order to make a page work.
- FrontAid 4y agoAnother similar gotcha is that the global-scoped `name` variable must be a string. See https://developer.mozilla.org/en-US/docs/Web/API/Window/name https://developer.mozilla.org/en-US/docs/Web/API/Window/name for details. 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.
- efdee 4y agoIt takes a special kind of human to name variable "name" but not have it be a string.
- orangecat 4y agoSomething like name = {first: "Jane", last: "Doe"} isn't obviously unreasonable. Which actually sets name to the string "[object Object]".
- eyelidlessness 4y agoFalsehoods programming languages believe about names.
- sanitycheck 4y agoI work with such humans! I was looking at that exact situation a few moments ago.
- Minor49er 4y agoI can imagine someone doing this if they were using "name" as a verb
- simlevesque 4y agoI've been doing JS for like fifteen years, this one I never knew. Wow. I must have never used "name" as a name for a global variable or just for ones that were strings.
- esprehn 4y ago
- twicetwice 4y agoiirc 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. [0]: https://www.robinsloan.com/notes/home-cooked-app/ https://www.robinsloan.com/notes/home-cooked-app/
- croes 4y agoIsn't the opposite of >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?
- bjkchoy 4y agoI 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!
- seba_dos1 4y ago> It did not even occur to me this was part of JS spec, It has nothing to do with JS spec; it's part of the DOM as defined by the HTML spec.
- debacle 4y agoI 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?).
- tfsh 4y agoCould you explain how rewriting one of the worlds most complex and critical specifications would break of the Google/MS hegemony on search?
- debacle 4y agoSorry, what I meant was: "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.
- doliveira 4y agoI 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
- eptcyka 4y agoThe best equipped to do this are Google/MS/Apple because they actually control the source code of relevant contemporary browsers.
- debacle 4y agoI think that this is the case (right now) because of Apple's stranglehold on the browser on iOS and the complex relationship between Google/Apple. 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.
- dfabulich 4y agoI'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. <!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.
- eyelidlessness 4y agoThere 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]. 1: https://github.com/tc39/proposal-shadowrealm https://github.com/tc39/proposal-shadowrealm 2: https://github.com/tc39/proposal-ses https://github.com/tc39/proposal-ses 3: https://github.com/tc39/proposal-built-in-modules https://github.com/tc39/proposal-built-in-modules
- dullcrisp 4y agoLuckily the Reddit thread has the Yu-Gi-Oh! jokes so I don't have to repeat them here.
- eyelidlessness 4y agoI don’t know what jokes or Reddit thread you’re referring to or why it has anything to do with my comment referencing three technical proposals, but I’ll take your word for it that you don’t have to repeat them here.
- mikessoft_gmail 4y ago
- esprehn 4y agoThe 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: https://source.chromium.org/chromium/chromium/src/+/main:out/Debug/gen/third_party/blink/renderer/bindings/modules/v8/v8_window.cc;drc=a432cd59d51281057ba2a2673ca645a9600bb927;l=21590?q=file:gen%20window.cc%20file:blink&ss=chromium%2Fchromium%2Fsrc https://source.chromium.org/chromium/chromium/src/+/main:out... to call this mess of security checks: https://source.chromium.org/chromium/chromium/src/+/main:third_party/blink/renderer/bindings/core/v8/custom/v8_window_custom.cc;drc=a432cd59d51281057ba2a2673ca645a9600bb927;l=186 https://source.chromium.org/chromium/chromium/src/+/main:thi... which has this interop surprise: https://source.chromium.org/chromium/chromium/src/+/main:third_party/blink/renderer/bindings/core/v8/custom/v8_window_custom.cc;l=281;drc=a432cd59d51281057ba2a2673ca645a9600bb927 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:third_party/blink/renderer/core/html/window_name_collection.cc;l=25;drc=a432cd59d51281057ba2a2673ca645a9600bb927 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!
- goatlover 4y agoIs 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.
- masswerk 4y agoBTW, in my experience getElementById() is still fastest.
- eyelidlessness 4y agoIn isolation definitely, but in real world code it might be faster to use querySelector for branchy code if it doesn’t always use an id. As with everything, if it’s not performance-sensitive write the code that’s easier for humans to read, and if it is measure first.
- beebeepka 4y agoThis 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
- 7952 4y agoI 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.
- stonewareslord 4y agoI 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! Here's a minimal example (https://jsfiddle.net/wc5dn9x2/ 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/ https://jsfiddle.net/wc5dn9x2/1/
- jefftk 4y agoNote that this is with the name attribute, not the id attribute the article is discussing.
- stonewareslord 4y agoGood catch. That would explain why it wasn't mentioned then
- dwild 4y agoCuriously the article doesn't mentions it, but theses kinds of vulnerabilities are named DOM clobbering if you want to know more about it! It's weirdly not that discussed on the web, most probably because it require a pretty specific situation.
- stonewareslord 4y agoThank you for this! I had a feeling it wasn't a security issue. I closed my ticket saying it might be one due to finding websites mentioning Dom clobbering
- tambourine_man 4y ago*rigamorale Should read “rigamarole”
- spdustin 4y ago*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.
- thunderbong 4y agoI've always thought it was 'rigmarole'! Today I learned, it's both! https://en.wiktionary.org/wiki/rigmarole https://en.wiktionary.org/wiki/rigmarole
- pkrumins 4y agoThis is my favorite HTML and JS feature!
- eithed 4y ago>To add insult to the injury, named elements are accessible as global variables only if the names contain nothing but letter. This doesn't seem to be true as shown within this fiddle: https://jsfiddle.net/L785cpdo/1/ https://jsfiddle.net/L785cpdo/1/ Bear in mind that only undefined elements will be declared this way
- mmazzarolo 4y agoAuthor here. That was a mistake on my part, it shouldn't have slipped in :) I removed that section, thanks for reporting!
- codedokode 4y agoIt would make sense to disable this with new release of HTML, for example if the author uses an HTML6 doctype.
- samtho 4y agoThis 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.
- deleted 4y ago[deleted]
- roberttod 4y agoFor 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.
- graderjs 4y agoAnd named form controls are accessible as properties of the same name on their form element.