When JS compiles your code, all the variable declarations var
you make go to the very top of their scope.
To be clear, that means when you declare a var
inside a function, it will go to the local top of that function block.
When it is outside a function, it will go to the very top, meaning global scope.
It's better to show an example:
console.log(myName);
var myName = 'Aaron';
a) Aaron
b) undefined
c) Uncaught ReferenceError: myName is not defined
var myName;
console.log(myName);
myName = 'Aaron';
Functions actually get hoisted to the top as well, above variable declarations as well.
Let's look at the example:
const hey = () => {
console.log('hey ' + myName);
};
hey();
var myName = 'Aaron';
a) hey Aaron
b) undefined
c) Uncaught ReferenceError: myName is not defined
const hey = () => {
console.log('hey ' + myName);
};
var myName;
hey();
myName = 'Aaron';
By the time the function gets called, the JS compiler knows there is a variable called myName
, but it will not know the value.
This might be the reason sometimes we see people declare variables right at the top, and then given values later.
Most likely, they are trying to mimic how the JS compiler actually sees the code to avoid any errors.
let
and const
are not hoisted. However, they differ in the way they are initialized.
By initialized, I mean the value they are given to begin with.
When we declare variables with var
or let
, they can initialized without a value.
Example:
var myName;
let myName;
// It will return undefined if you call either of these
const
on the other hand needs to have a value
The following below are examples that don't work:
const myName;
// This will throw a reference error
const myName;
myName = 'Aaron';
As you probably know, any variables used with var
can be accessed from outside of their initial scope.
let
and const
on the other hand can not be accessed outside of their initial scope. Order matters here.
Examples:
console.log('1', myName1); // returns 1 undefined
if (true) {
console.log('1a', myName1); // returns 1a undefined
var myName1 = 'Aaron';
}
console.log('2', myName2); //error: myName2 is not defined
if (true) {
console.log('2a', myName2);
let myName2 = 'Aaron';
}
console.log('3', myName3); //error: myName3 is not defined
if (true) {
console.log('3b', myName3); // undefined
const myName3 = 'Aaron';
}
We can observe that variables declared with var
return undefined
while let
and const
return errors.
This is because let
and const
stay exactly where they are placed. It can not move like a var
declaration.
var myName1;
console.log('1', myName1); // returns 1 undefined
if (true) {
console.log('1a', myName1); // returns 1a undefined
myName1 = 'Aaron';
}
console.log('2', myName2); // Uncaught ReferenceError: myName2 is not defined
if (true) {
console.log('2a', myName2); // Uncaught ReferenceError: Cannot access 'myName2' before initialization
let myName2 = 'Aaron';
}
console.log('3', myName3); // Uncaught ReferenceError: myName3 is not defined
if (true) {
console.log('3b', myName3); //Uncaught ReferenceError: Cannot access 'myName3' before initialization
const myName3 = 'Aaron';
}
It's good to be aware of the nuances of JS, even if you don't really think about it everytime you code.
Hoisting is just a quirk of JS -- not really a topic to stress about, but can be useful if debugging or trying to get into the more advanced topics of JS.