If you want to put your script
tag in the <head>
of a document, you're probably familiar with putting things into the DOMContentLoaded
event:
document.addEventListener('DOMContentLoaded', () => {
doThings();
doOtherThings();
});
function doThings() { ... }
function doOtherThings() { ... }
However, this can lead to some issues when trying to read HTML elements in multiple functions. You might instinctively move the elements up a scope, but that won't work:
document.addEventListener('DOMContentLoaded', () => { ... });
// nope
const thing = document.getElementById('thing');
function doThings() {
thing.class = 'whatever';
}
function doThings() {
thing.class = 'now-this';
}
thing
won't be accessible at that point because it's outside DOMContentLoaded
, which means the JS interpreter will try to resolve it before the DOM is loaded, and come up empty. Putting elements in the loaded event won't work either:
document.addEventListener('DOMContentLoaded', () => {
const thing = document.getElementById('thing');
doThings();
doOtherThings();
});
Because as you know, even though thing
WOULD be loaded now, it's no longer in a higher scope than where the functions are defined. Again, our functions won't have access. So, what are we going to do? We could redefine thing
inside every function, but that's not exactly DRY.
A more elegant solution is to use a main
function. The idea is to put everything, every single line, inside a function, and then call that function on DOMContentLoaded
:
const main = () => {
const thing = document.getElementById('thing');
function doThings() {
thing.class = 'whatever';
}
function doThings() {
thing.class = 'now-this';
}
}
document.addEventListener('DOMContentLoaded', main);
By the time main
gets called, we have full access to our DOM, so we can reference it anywhere inside main
without issues, including in our functions.
You absolutely could. This setup is essentially mimicking what would happen if you put it just before the closing <body>
tag. Or is it? Apparently, some browsers can now load pages asynchronously, so even if you put your script at the bottom of the page, the DOM may not yet be fully done. Leading to inconsistent behavior. In some browsers. Maybe.
So if you want to fully cover your bets, the safest thing to do is wrap all your content in a function and then call that only once the loaded event fires. Whether or not it's in the <head>
or <body>
tag is up to you to determine. I can't seem to find a solid answer as to which is truly "best," which means as long as you can explain why you chose what you did to an interviewer, you're fine.