Hoisting is small concept that’s pretty important
Hoisting is a concept that really defines a fundamental principle of JavaScript: there’s no such thing as block scope.
What does that mean? Well, we know there’s a thing called function scope:
Function scope example
… Easy.
But how do we define block scope? In some other languages, it might be whatever is inside an if
statement or a for
loop. But that doesn’t exist in JavaScript (well, with a caveat, which we’ll go over in a later section):
If-statement example
The above example is super easy to understand. But let’s try and do something else with it.
Trying to use block scope in JavaScript
In the above example, if you didn’t know any better and you thought JavaScript had block scope, you might assume that the variable foo
only exists inside the if
block. But it doesn’t. In fact, even if the condition in the if
statement evaluated to false, the variable foo
would still exist to the entire function, but it just would not be set to 'bar'
(it would actually just remain undefined
).
So what’s hoisting then?
Anything defined inside of a block is actually “hoisted” up to the function scope of whatever function you’re in.
Anything you declare inside of a block (whether it’s a function, a string, an array, or whatever), it is available to the entire scope. Blocks simply evaluate those variable to whatever you say, when a certain condition is met.
Best Practice
In my opinion, declaring all variables that will, or even just might, be later defined within your function should happen at the top of the function. Some arguments against this might cite possible performance issues, but that might be going into the arguments of micro-optimization vs readability.
In my opinion, declaring all variables that will, or even just might, be later defined within your function should happen at the top of the function
I humbly assert this opinion because I think it helps immensely with code readability, especially with large, wordy functions, and understanding ahead of time what is going to happen and what certain variable might get new definitions.
In the above example, you know all the variables ahead of time, even though only one of them might actually be set to something else other than undefined
(in this case, only one of those variables might be set to 0
).
To me, this looks like it could get confusing:
While this is a small, manufactured function that probably doesn’t make sense and probably does a whole lot of nothing, in a lengthier function, someone else who reads the code might see a new variable definition, and have trouble understanding the context or the use. Additionally, all those variable declarations will get hoisted to the top of the function anyway. You’ll still have three variables that are undefined
, and only one that is set to 0
, but the code just happens to be more confusing.
Small caveat regarding let
If you use the keyword let
in place of var
, everything I just wrote in this blog post is null and void. let
allows you to declare and/or define a block-scoped variable (see the MDN page, which says “The let statement declares a block scope local variable, optionally initializing it to a value.”)
Note this warning on the MDN page as well:
The let block and let expression syntax is non-standard and will be removed in the future. Do not use them!