var, let, and const in JavaScript: Scope, Hoisting, Redefinition, and Reassignment

In the past, we used the var keyword to create new variables. Modern JavaScript introduces two new ways to declare variables: let and const.

Today, we'll discuss the differences between them. To do that, let's first talk about the differences between let and var.

let vs var

Let's discuss the var keyword first.

Variables declared with var can have either global or local scope. Global scope applies to variables declared outside of functions, while local scope applies to variables declared inside functions.

var greet = "Hello";
console.log(greet); // Hello

In the example above, I've declared greet as a global variable. This global variable greet can also be used within a function, like this:

var greet = "Hello";
function sayHello() {
  console.log(greet);
}

sayHello(); // Hello

However, the reverse is not true. If I declare a variable inside a function, I cannot use it outside the function.

function sayHello() {
  var greet = "Hello";
  console.log(greet);
}

sayHello(); // Hello
console.log(greet); // Uncaught ReferenceError: greet is not defined

So, we can conclude that var is function-scoped. This means that a variable created with var in a function will only exist within that function.

If the variable is created outside of the function, it will exist in the outer (global) scope.

var greet = "Hello"; // global scope

function sayHello() {
  var greet = "Hi"; // local scope
  console.log(greet);
}

sayHello(); // Hi
console.log(greet); // Hello

Variables declared with var can also be redeclared.

var greet = "Hello";
console.log(greet); // Hello

var greet = "Hi";
console.log(greet); // Hi

Also, variables declared with var are hoisted to the top of their function or global scope, which means they are accessible before the line where they are declared.

console.log(greet); // undefined

var greet = "Hello";

console.log(greet); // Hello

let, on the other hand, is block-scoped. This means whenever a variable is created with let, it will only exist within its block.

But wait, what’s a block?

A block in JavaScript is anything within a pair of curly braces. The following are examples of blocks.

{
  // new scope block
}

if (true) {
  // new scope block
}

while (true) {
  // new scope block
}

function () {
  // new block scope
}

The difference between block-scope and function-scoped variables is huge. When you use a function-scoped variable, you may accidentally overwrite a variable without intending to do so. Here’s an example:

var greet = "Hello";

if (true) {
  var greet = "Hi";
}

console.log(greet); // Hi

In this example, you can see that greet becomes Hi after running through the if block.

As you can see, block-scoped variables make development much simpler by removing common gotchas with function-scoped variables. To make life simple, I recommend you use let over var whenever you declare JavaScript variables from now on.

Just like var, variables declared with let can be reassigned to other values, but they cannot be redeclared.

let greet = 'Hello`
console.log(greet) // Hello

greet = 'Hi'
console.log(greet) // Hi

Variables declared with let are also hoisted to the top of their global, local, or block scope, but their hoisting is a little different from the one with var.

var variables are hoisted with a default value of undefined, which makes them accessible before their line of declaration (as we've seen above).

But, let variables are hoisted without a default initialization. So when you try to access such variables, instead of getting undefined, or variable is not defined error, you get cannot access variable before initialization. Let's see an example:

console.log(greet);
// ReferenceError: Cannot access 'greet' before initialization

let greet = "Hello";

Now we know what let does, let’s move on to the difference between let and const.

let vs const

Like let, const is also blocked-scoped. The difference is that const cannot be reassigned once declared.

const greet = "Hello";
greet = "Hi"; // TypeError: Assignment to constant variable.

let greet1 = "Hello";
greet1 = "Hi";
console.log(greet1); // 'Hi'

Since const cannot be reassigned, they’re good for variables that would not change.

When declaring variables, I always prefer const over let whenever possible because I receive the extra cue that the variable would not get reassigned. Then, I use let for all other situations.

Summary

Here's a table summary showing the differences between these keywords:

Table summary

Get my free, weekly JavaScript tutorials

Want to improve your JavaScript fluency?

Every week, I send a new full-length JavaScript article to thousands of developers. Learn about asynchronous programming, closures, and best practices — as well as general tips for software engineers.

Join today, and level up your JavaScript every Sunday!

Thank you, Taha, for your amazing newsletter. I’m really benefiting from the valuable insights and tips you share.

- Remi Egwuda