How function hoisting enables you to write clearer code
Published
When we talk about writing readable code, one of the most crucial aspects is to recognise that code is meant to be read by humans first and foremost.
One key principle is that you should not force the reader to understand or process every little detail all at once. Think of your code like a well-written newspaper article. When you read a news article, you start with the headline—broad and essential information. Then, as you continue reading, the story deepens, with more detailed explanations that follow in the later paragraphs. This structure allows the reader to get the most critical information up front and dig deeper only if they want or need to. Crucially, the reader can bail out when they want to. Good code should work the same way.
Function hoisting in JavaScript, as opposed to arrow functions (which need to be declared before they’re used), support this kind of readability. In JavaScript, function declarations are hoisted, meaning that you can declare a function anywhere in the code, and it can still be invoked before its declaration. This allows you to place your most important logic (like the main flow of your program) at the top, where it is immediately visible and understandable, without needing to wade through the implementation details of every helper function that supports that logic.
By organising your code this way, the reader can get the "headline" (i.e., the high-level logic) up front. They don't need to scroll down through the helper functions to see what the program is doing. Only if they're interested in the details of how a specific task is done do they need to follow the breadcrumbs into those helper functions.
For example, consider this code structure:
function mainTask() {
// high-level logic, easy to read
setup();
process();
finalize();
}
function setup() {
// detailed code for setting things up
}
function process() {
// detailed code for processing
}
function finalize() {
// detailed code for finalizing
}
With function hoisting, the reader can start with the mainTask
function and immediately understand the high-level
flow of the program. If they want more details on how setup
, process
, or finalize
works, they can read further
down. But if they don't need that level of detail, they can bail out after seeing the structure and purpose.
On the other hand, arrow functions, which are not hoisted, force you to declare them before they are used. This can make your code harder to read at first glance, because the reader must sift through low-level implementation before understanding the bigger picture:
const setup = () => {
// detailed code for setting things up
};
const process = () => {
// detailed code for processing
};
const finalize = () => {
// detailed code for finalizing
};
const mainTask = () => {
// now the high-level logic
setup();
process();
finalize();
};
In this second example, by the time the reader gets to the high-level mainTask
logic, they’ve already seen the details
they might not care about, and they had no chance to get an overview first.