Hoist the Variables and Scuttle the Jib!
This is the second in a series of posts that will discuss questions I was asked during my recent mock technical interview about JavaScript.
One of the questions posed during the interview asked me to explain hoisting. A fairly recent term in the JavaScript world, hoisting refers to how a variable or function can be initialized and used prior to being declared. Consider the following examples:
say = “Say what???”;console.log(say);var say;
____________________
sayWhat();function sayWhat() {console.log(“Say what???”);}
What do you think will be logged to the console in each case? Will we get “Say what???”, or will we get an error?
We get… “Say what???”
In the first example, we see the variable say declared at the end, and in the second example, the function call comes before the function declaration, yet the code in each case works the same as if the declarations had appeared first. This is due to the magic of hoisting.
Declarations only, please!
Keep in mind that hoisting only applies to variable declarations and function declarations. The key word here is declarations. This principle doesn’t work with initializations.
For instance, these examples would return a value of “undefined”:
console.log(say);say = “Say what???”;var say;
___________________
console.log(say);var say = “Say what???”;
Why? Only the declaration of the variable say is hoisted, not the initialization. Because say has still not been assigned a value when “console.log” runs, we get “undefined”.
Also, a function expression assigned to a variable will not be hoisted, as in the following example:
say();var say = function() {console.log(“Say what???”);}
If you do this, you’ll get a lovely message: “Uncaught TypeError: say is not a function”. Again, this is because functions get hoisted, not function expressions. You’ll get the same error message if you try this with an arrow function.
Hoisting with Let and Const
The above examples employed the var keyword. What if we were to use let and const?
Let’s try this out.
say = “Say what???”;let say;console.log(say);
What’s our result? Uh oh, an error message: “Uncaught ReferenceError: Cannot access ‘say’ before initialization”. What’s going on here? Well, when using let, a variable must be declared before it can be used.
And if we try this with const?
say = “Say what???”;const say;console.log(say);
Oh great, another lovely error message: “Uncaught SyntaxError: Missing initializer in const declaration”. W3Schools.com explains it this way: “Variables defined with let and const are hoisted to the top of the block, but not initialized. Meaning: The block of code is aware of the variable, but it cannot be used until it has been declared.” So trying to hoist with let and const is no-no.
To hoist, or not to hoist?
During my mock technical interview, I remarked that I didn’t know why anyone in their right mind would rely on hoisting. My interviewer agreed with me that it could lead to buggy code and that he therefore didn’t care to use it. The bottom line is that it’s best practice to do as W3Schools.com advises: “Declare your variables at the top!”