JavaScript Fundamentals: Variables and Hoisting
By: Cody Dupuis
Tags: Var, Const, JavaScript, Let, Variables

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 and undefined .

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 break let 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 right const 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 break const x = 5;

const x = 6;

// this will also break const 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 reassigned dev.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!