“let” vs “var” in JavaScript: A Comprehensive Guide (Examples)

The main difference between let and var in JavaScript is:

  • var declarations are function-scoped.
  • let declarations are block-scoped.

This means you can have multiple let variables with the same name as long as they live in different scopes, such as in different functions.

For instance:

let x = 10

if(true){
    let x = 1000
    console.log(x) // 1000
}

console.log(x) // 10

In addition to this, there is a bunch of important differences, such as hoisting. These are important to understand to truly be able to tell the difference between let and var in JavaScript.

In this guide, you learn what is the difference between var and let in JavaScript. You are going to:

  • Understand problems with var.
  • What is hoisting in JavaScript?
  • How to solve problems with var using the let variables.
  • What is a constant (const) and how does it differ from var and let variables?

Let’s start by introducing variables created with the var keyword. In the past, this was the only way to create a variable in JavaScript.

‘var’ in JavaScript

In JavaScript, you can declare a variable using the var keyword.

For example:

var x = 10

You can then access this variable by calling its name.

But where can you do this? What if there is another variable with the same name?

To know the answers to these questions, let’s discuss the scope of this variable.

Scope of a ‘var’ Variable

In JavaScript, scope refers to accessibility.

When talking about variables, the scope means those places in the code where the variable is available.

The scope of a variable created with var can be one of these two:

  1. Global scope if the variable declaration happens outside a function.
  2. Function scope if the declaration takes place inside a function.

To understand what these mean, let’s have a look at a bunch of examples.

var num1 = 10

function example(){
    var num2 = 100
}
  • Here, the variable num1 has a global scope, because it is not surrounded by a function. This means you can access the variable num1 anywhere in the code.
  • The variable num2 is not globally scoped because it’s defined inside a function example(). Instead, it has function scope. This means you cannot access the variable from anywhere else than within the function.

To demonstrate this, consider this piece of code:

var num1 = 10;

function example(){
    var num2 = 100;
    console.log(num2); // output: 100
}

console.log(num1); // output: 10
console.log(num2); // error: Uncaught ReferenceError: num2 is not defined

As you can see, logging num2 outside of the function example() is not possible. Instead, it results in an error due to the variable num2 being defined only in the scope of the function.

Now that you understand what is a var and is its scope, let’s talk about re-declaring a variable.

Re-Declaration of a ‘var’ Variable

You can re-declare variables created with the var keyword.

In other words, you can specify a variable and then create a new variable with the same name.

This action naturally overrides the original variable.

For example, this piece of code creates a variable called number and then re-declares that variable with a different value:

var number = 100
var number = 25

From this point on, the number is 25, not 100.

This piece of code does not cause any issues.

However, this behavior can be an issue in specific situations.

Let’s take a look at this piece of code:

var num = 10

if(true){
    var num = 99
    console.log(num)
}

console.log(num);

Output:

99

As you can see, the if statement changes the variable num permanently.

This change applies even outside of the if statement.

This kind of behavior may cause confusion.

One might expect that inside the if statement, the variable num would be treated as a different num variable than the globally scoped variable num.

This is one example of an issue caused by declaring a variable using the var keyword.

Before solving this problem, let’s talk about hoisting.

Hoisting of ‘var’ Variables

hoisting in code vs under the hood in javascript
Hoisting moves declarations on the top of the scope.

Hoisting in JavaScript means variable and function declarations are moved to the top of the scope before the code runs.

This happens because JavaScript wants to look ahead of the code about to be executed and reserve space for variables and functions.

Hoisting makes it possible to call a variable before even defining it.

For example, you probably would expect this piece of code to cause an error:

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

But instead of crashing, it spits out:

undefined

This happens because of what is called hoisting

Under the hood, the above piece of JavaScript code translates to this:

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

In other words, here is what happens behind the scenes:

  1. The variable greet is declared but not defined. This assigns undefined to it.
  2. Then the variable greet is displayed in the console. Because the variable is undefined, this shows undefined in the console.
  3. In the last line, we assign “Hello” to the variable.

To recap, all the variables created using var are hoisted to the top of the scope and are assigned a value of undefined.

The hoisting process introduces an issue that can cause headaches.

Let’s see an example that demonstrates this issue:

var name = "Charlie"

function getName() {
  if(!name){
    var name = "James"
  }

  return name
}

console.log('Your name is', getName())

Output:

Your name is James

This is confusing.

The code states:

  1. If the name is not defined, create a variable called name.
  2. Assign “James” to name.
  3. Return the name.

But in the above example name is “Charlie” to begin with.

Thus the if-check should never pass and the function getName() should always return “Charlie”.

But based on the output, this is not true.

But why is that?

Due to hoisting, the name is undefined in the line where the if check happens. This means the condition !name evaluates to true. Thus the if-check is passed and “James” gets assigned to the variable name.

To better understand why the name is undefined, let’s inspect how the above function looks under the hood due to hoisting:

var name = "Charlie"

function getName() {
  // The 'name' is hoisted before the if statement. This makes it 'undefined'
  var name
  if(!name){
    name = "James"
  }

  return name
}

console.log('Your name is', getName())

As you know, hoisting moves all the declarations to the top of the scope.

In the getName() function, this means the variable name is redeclared before the if-check and assigned a value of undefined.

This is why the if-check is passed and the name “James” is returned.

If you did not know about hoisting, this kind of behavior would be impossible to wrap your head around.

Next, let’s learn how to fix these issues with the let keyword.

‘let’ Keyword in JavaScript

The preferred way to declare variables in JavaScript these days is using the let keyword.

This became an option since ES6.

The let keyword was introduced to improve creating variables in JavaScript.

var and let in javascript code

In this section, you learn why let is better than var.

The Scope of a ‘let’ Variable

The let variable has a block scope.

Thus a let variable is only accessible in-between the curly braces where it’s defined.

For example, accessing a let variable outside of a block results in an error:

if(true){
    let num = 1
}

console.log(num)

Output:

error: Uncaught ReferenceError: num is not defined

This error happens because the num variable is only accessible inside the if statement.

Block scoping lets you have two variables with the same name in different scopes.

For example:

let num = 1

if(true){
    let num = 20
    console.log(num)
}

Output:

20

Now, instead of redeclaring the num, both num variables are treated as different variables in their own scopes.

This makes let a better choice than var.

When using let, you don’t have to worry if you have used the variable’s name before.

Re-Declaration of a ‘let’ Variable

As opposed to var, a let variable cannot be re-declared within its scope.

For example, this results in an error:

let number = 100
let number = 25

Output:

Identifier 'number' has already been declared.

Hoisting ‘let’ Variables in JavaScript

As you already learned, each declaration is hoisted in JavaScript.

This applies to let variables too.

The difference between hoisting let and hoisting var is:

  • var variable is hoisted so that undefined is assigned to it
  • let variable is hoisted without any initial value.

This means you cannot access a variable created with let before defining it:

console.log(greet)
let greet = "Hello"

Output:

error: Uncaught ReferenceError: Cannot access 'greet' before initialization

Let’s go back to the issue you saw earlier with variables created using var:

var name = "Charlie"

function getName() {
  if(!name){
    var name = "James"
  }

  return name
}

console.log('Your name is', getName())

As you may remember, this piece of code results in a somewhat unexpected output:

Your name is James

To fix this problem, you should use a let variable instead.

For example:

let name = "Charlie"

function getName() {
  if(!name){
    let name = "James"
  }

  return name
}

console.log('Your name is', getName())

Output:

Your name is Charlie

Now the if statement never succeeds.

This because because of hoisting. Now the name is not undefined. Instead, the name “Charlie” is used outside of the function as you’d expect.

As mentioned earlier, this guide would not be complete without talking about the const keyword which makes it possible to introduce constants in JavaScript.

‘const’ in JavaScript

A variable declared as const maintains a constant value in JavaScript.

The only real difference between const and let is that const is immutable.

This means that once defined, you can never change its value.

For example:

const num = 1
num = 20

Output:

error: Uncaught TypeError: Assignment to constant variable.

With this constraint, const must be initialized during declaration.

Other than being immutable, const behaves like let. Let’s talk about the scope of the const to further understand this similarity.

Scope of ‘const’ Constants

Similar to letconst has a block scope.

This means the const variable can only be accessed within the curly braces in which it’s defined.

For example:

if(true){
    const num = 10;
    console.log(num) // success
}
console.log(num) // failure

Also, you can have many const variables with the same name in different scopes, because they’re treated as different variables.

For example:

const num = 1

if(true){
    const num = 20
    console.log(num)
}

Output:

20

Re-Declaration of a ‘const’ Constant

You cannot re-declare a constant in JavaScript.

For example, this piece of code causes a syntax error:

const x = 10
const x = 1000 // SyntaxError: Identifier 'x' has already been declared

However, due to the block scope of the const, you can have multiple constants with the same name as long as they are in different scopes.

For example:

const x = 10

if(true){
    const x = 1000
    console.log(x)
}

console.log(x)

Output:

1000
10

Hoisting the ‘const’ Constants

Hoisting const and let work the same way.

They are not initialized with the value of undefined beforehand, instead, they’re not initialized at all. This makes it impossible to call them before initializing them.

For instance:

console.log(greet)
const greet = "Hello"

Output:

error: Uncaught ReferenceError: Cannot access 'greet' before initialization

Conclusion

The old-school way of creating variables in JavaScript was using var.

As of ES6, there’s been a more consistent approach for creating variables using let.

Also, an ES6 way to create a constant is by using the const keyword.

The differences between var and let in JavaScript are:

  1. Scope
    • var declarations are function-scoped.
    • let variables be block-scoped.
  2. Re-declaration
    • var variables can be updated and re-declared within the scope.
    • let variables can be updated but not re-declared.
  3. Hoisting
    • var variables are hoisted with an initial value undefined.
    • let variables are not hoisted with an initial value.

Thanks for reading.

Scroll to Top