JavaScript Fundamentals: Variables and Hoisting
Today I’m going to cover a few different kinds of variables in JavaScript. We have three types of variables to choose from when declaring: var
, let
, and const
. In this article, I’ll be doing a quick comparison of the three and working in the term hoisting as well.
What is Hoisting?
Hoisting is JavaScript’s default behavior of moving all variable declarations to the top of the current scope or function. In order to truly grasp the concept, we need to understand the difference between variable declaration and variable initialization.
Declaring a variable is as simple as saying var x;
. You’re quite literally declaring its existence. It doesn’t do anything yet, but you’re announcing its presence.
Initializing a variable is taking that x
variable and assigning it a value. So the statement x = 5;
is an initialization since now the variable has an assigned value.
You can declare and initialize a variable in the same line:var x = 5;
Where does hoisting fit into all of this? Well, only declarations are hoisted, initializations or assignments are not. Let’s start with this example:
var x;
console.log(x);
x = "Hello";//////////////////console.log(x);
var x = "Hello";
Both of these examples will log undefined
in the console. That’s because at the point of execution at the console.log()
statement, you’re asking the script to log a variable that exists, but at this moment in execution does not contain an assigned value. However, if the order is rearranged:
x = "Hello";
console.log(x);
var x;
This example will actually log "Hello"
to your console thanks to hoisting. When JavaScript compiles, it’ll take that statement at the bottom and hoist it to the top, so at the point where it reaches the console.log()
statement, the variable x
already has an assigned value.
A simple fix to this slight complication is just to assign and declare your variables at the top of the scope:
var x = "Hello";
console.log(x);
Best programming practice is to declare your variables like such anyway, unless for some specific reason you absolutely cannot do so.
Although only the declarations of variables declared with var
are hoisted, they can be initialized at any time. In reference to the very first example above, the exact same example but with let
instead of var
will throw a ReferenceError:
let x;
console.log(x)
x = 'Hello";
This code will break simply because in the case of using let
, the declaration of the variable gets hoisted, but the variable doesn’t get initialized. Same goes for const
in this example.
This is the major difference between the old variable var
and the new variables let
and const
. The easiest way to grasp the differences is to describe the difference between var
and let
, then move on to let
vs. const
.
Var vs. Let
Scope
Any variable declared using the old variable type var
is defined in global scope or function scope. A simple example:
var x = 5;function scopeExample() {
var y = 6;
console.log(x, y);
}console.log(x, y);
x
is declared in global scope, meaning the console.log()
statement inside of the function scopeExample()
will return 5 and 6.
y
on the other hand is declared in function scope, meaning only code within the same function has access to it. The console.log()
statement at the very bottom will return 5 andundefined
.
The same example above can be used with let
and show the same results. The main difference between var
and let
here is that var
variables declared globally are attached to the JavaScript’s window
object, and the let
variables are not.
Let’s try a new example:
let y = 5;{
var x = 5;
let y = 6;
console.log(x, y);
}console.log(x, y);
This new example is an example of block scope, a new kind of scope that was introduced with the new variables. It works very similarly to function scope. So what’s the difference then?
var
does not contain any kind of block scope. The x
value that will be logged in both console.log()
statements will be 5.
let
is bound to block scope, which means the first console.log()
statement inside of the block will return 6 for y
, whereas the console.log()
statement at the very bottom will return 5.
Reassignments & Redeclarations
When using var
, you can reassign or redeclare that variable wherever in the program:
var x = 5;
{
var x = 6;
}
console.log(x);
This console.log()
statement will return 6.
When using let
, the variable can be reassigned, but can not be redeclared:
let x = 5;
let x = 6;
// this code will breaklet x = 5;
x = 6;
// this is perfectly fine
Also, you cannot redeclare a var
variable with let
, just in case you were wondering:
var x = 5;
let x = 6;
// this code will break
Now we need to talk about loop scope. If you have a global var
variable followed by a loop with var
being used, the global variable will be reassigned. For example:
var i = 10;for (var i = 0; i < 12; i++) {
console.log(i);
}console.log(i);
In this example, we have a global variable initialized with a value of 10, and then we have a loop iteration that will console.log()
every time our i
variable is incremented. In this example, your console will log every number 0 through 12, then log 12 again. This is because on the line where we declare var i = 0
for the loop, the variable at the top gets reassigned.
This is not the case with let
:
let i = 10;for (let i = 0; i < 12; i++) {
console.log(i);
}console.log(i);
This example will log every number 0 through 12 from the loop, but at the very end will log 10. Thanks to let
having access to block scope, the second variable declaration only exists within the block, and the global variable is unaffected.
Now that we are feeling comfortable with the differences of var
and let
, let’s discuss what makes let
different from const
.
Let vs. Const
In the above section, for the most part, you can substitute const
for let
and it would remain true. Const
is bound to block scope while var
is not.
The main difference that sets const
apart from the other two is its declaration and reassignment properties.
When declaring a const
variable, it must be initialized in the same statement:
const x = 6;
// this is rightconst x;
// this will break
Additionally, unlike the other two, const
cannot be redeclared or reassigned, unless done so inside of a different scope:
const x = 5;
x = 6;
// this will breakconst x = 5;
const x = 6;
// this will also breakconst x = 5;
{
const x = 6;
}
// this will not break as its technically two different variables
const
variables can hold different data types, such as arrays and objects. Those can be modified through methods:
const pets = ["cat", "dog", "bird"];
pets.push("fish");
// pets #=> ["cat", "dog", "bird", "fish"]pets[0] = "hamster"
// pets #=> ["hamster", "dog", "bird", "fish"]pets.pop();
// pets #=> ["hamster", "dog", "bird"]
const dev = {name: "Cody", experience: "Junior"}dev.experience = "Senior";
// properties can be reassigneddev.fatigue = "low";
// properties can be added
// dev #=> {name: "Cody", experience: "Senior", fatigue: "low"}
Conclusion
I hope this was informative and helped you grasp the complexities between JavaScript’s different variables. Thank you for reading and happy coding!