There is a common misconception that hoisting means declarations are hoisted or brought to the top of the file, and are therefore available to be used anywhere in the module, but this interesting snippet from MDN says otherwise:
Conceptually [...] a strict definition of hoisting suggests that variable and function declarations are physically moved to the top of your code, but this is not in fact what happens. Instead, the variable and function declarations are put into memory during the compile phase, but stay exactly where you typed them in your code.
With these declarations already in memory, we can use them anywhere in the module, including when importing code, which allows us to declare imports and exports pretty much anywhere (note that I'm not sure why you would want to make a habit out of this, but it's possible to do so):
index.mjs
foo()
import foo from './foo.mjs'
foo.mjs
export default foo
function foo() {
console.log('hello hello')
}
Although it's another topic, one reasonable place you might want to require
/import
something midway through a file is to dynamically import things, maybe like:
...
async function lazyLoad() {
const module = await import('./module.mjs')
// do some cool stuff here
}
...