DEV Community

Cover image for What is up with var, let and const? What the hell is the difference between these three?
Shubhra Agarwal
Shubhra Agarwal

Posted on

What is up with var, let and const? What the hell is the difference between these three?

With ES2016 came two new methods to declare variable i.e. let and const. Before that the developers had access to only var(I feel bad for them, no kidding).

So, what's the catch here? Why are there three different ways to declare variables? Wasn't JavaScript already confusing enough and now they're making it more confusing.

Before we can understand how var and let/const differ we need to understand a computer science-y concept called scope.

Function scope vs Block Scope

JavaScript comes with two kinds of scope i.e Function scope and block scope. Let's have a look at the difference in both of them.

Function Scope

function myFn() {
  var foo = 'peekaboo!';

  console.log(foo); // 'peekaboo!'
}

console.log(foo); // ReferenceError: foo is not defined
Enter fullscreen mode Exit fullscreen mode

Variables are function-scoped when using var because their visibility is restricted to the function. You'll get an error if you try to utilise it outside of the function.

Block Scope

if (true) {
  var foo = 'peekaboo!';
  let bar = 'i see u';
  const baz = 'baby blue!';

  console.log(foo); // 'peekaboo!';
  console.log(bar); // 'i see u';
  console.log(baz); // 'baby blue!';
}

console.log(foo); // 'peekaboo!';
console.log(bar); // ReferenceError: bar is not defined
console.log(baz); // ReferenceError: baz is not defined
Enter fullscreen mode Exit fullscreen mode

Notice the visibility of foo isn’t limited by the if-statement block. However, both bar and baz are limited in visibility to the block of code.

This concept of scope is the most prominent distinction between the old-fashioned var and modern let/const.

image

Source: https://twitter.com/mpjme

VAR

Let's have a look at the following code snippet

for (var i = 0; i < 3; i++) {
  console.log(i);
}

console.log(i);
Enter fullscreen mode Exit fullscreen mode

According to you what will be the output of the following program??
If you said

//0
//1
//2
//3
Enter fullscreen mode Exit fullscreen mode

then you're absolutely correct.

The variable i is accessible outside of the for-loop. This is expected since variables defined with var have a function scope rather than a block scope i.e they're accessible within the whole function in which they are defined in.

If it's so cool then what's the problem with using var? Why aren't we using it?

I'll use the example below to explain:

    var greeter = "hey hi";
    var times = 4;

    if (times > 3) {
        var greeter = "say Hello instead"; 
    }

    console.log(greeter) // "say Hello instead"
Enter fullscreen mode Exit fullscreen mode

So, since times > 3 returns true, greeter is redefined to "say Hello instead". While this is not a problem if you knowingly want greeter to be redefined, it becomes a problem when you do not realise that a variable greeter has already been defined before.

If you have used greeter in other parts of your code, you might be surprised at the output you might get. This will likely cause a lot of bugs in your code. This is why let and const are necessary.

In layman terms, var can be redefined and it's values can also be changed?

So Shubhra, what can we do to save ourselves from making such blunder in production code???

Well, worry not, the people in the JavaScript headquaters knew that you would be having this problem and already gave a solution for this.

Here comes let to save the day.

LET

In many ways let is like a cousin of var. It has a lot of similarities but differentiates in ways that makes ES2016 a more modern-feeling language.

Let us take the same example we took in var

for (let i = 0; i < 3; i++) {
  console.log(i);
}

console.log(i);
Enter fullscreen mode Exit fullscreen mode

This time what do you think the output is going to be?? Well if you said

//0
//1
//2
//ReferenceError: i is not defined
Enter fullscreen mode Exit fullscreen mode

then you're in luck.

Hey Shubhra, if let is a cousin of var then why is it coming undefined?
Let me tell you, so let is blocked scope instead of being function scoped.

let can be updated but not re-declared.

Just like var, a variable declared with let can be updated within its scope. Unlike var, a let variable cannot be re-declared within its scope. So while this will work:

    let greeting = "say Hi";
    greeting = "say Hello instead";
Enter fullscreen mode Exit fullscreen mode

this will return an error:

    let greeting = "say Hi";
    let greeting = "say Hello instead"; // error: Identifier 'greeting' has already been declared
Enter fullscreen mode Exit fullscreen mode

However, if the same variable is defined in different scopes, there will be no error:

    let greeting = "say Hi";
    if (true) {
        let greeting = "say Hello instead";
        console.log(greeting); // "say Hello instead"
    }
    console.log(greeting); // "say Hi"
Enter fullscreen mode Exit fullscreen mode

Why is there no error? This is because both instances are treated as different variables since they have different scopes.

This fact makes let a better choice than var. When using let, you don't have to bother if you have used a name for a variable before as a variable exists only within its scope.

Also, since a variable cannot be declared more than once within a scope, then the problem discussed earlier that occurs with var does not happen.

CONST

The keyword const is an abbreviation for constant. Similar to let, it’s block-scoped, however, you can’t reassign it.

What do you think is the output of this code?

const myBoolean = true;

if (myBoolean) {
  const turtles = [
    'leonardo',
    'donatello',
    'michaelangelo',
    'raphael'
  ];
  // turtles = turtles.concat('Shredder');  // 🙅‍♀️ this would throw an error

  console.log(turtles);
}

console.log(turtles);
Enter fullscreen mode Exit fullscreen mode

The output

// ['leonardo', 'donatello', 'michaelangelo', 'raphael']
// ReferenceError: turtles is not defined
Enter fullscreen mode Exit fullscreen mode

Because the const is not transferred in this scenario, items can still be added to a const variable that links to an array or an object.
This is a topic for another blog. I will discuss it later.

Conclusion

Because function-scope isn't as evident as block-scope, it's best to avoid using var. The objective of ES2016-2019 appears to be to replace var with let/const because they encourage better code habits.

If you need to construct a variable, you should usually use const. Use let instead if you know or suspect you'll need to reassign it (for-loops, switch statements, algorithm swapping).

Discussion (1)

Collapse
thumbone profile image
Bernd Wechner

Nice summary and I admire your curiosity and diligence in exploring it. For my part I simply accepted that var is essentially deprecated and let and const its modern replacements. I won't change that, meaning I have avoided using var for ages and routinely replace it with let or const as appropriate (and retest).