Variable Declarations in JS - let vs const vs var

Payal RatheePayal Rathee
4 min read

This article focuses on the three important keywords that lets you define variables and constants in Javascript - var, let and const.

Before we dive into the working and behavior of these keywords, make sure you understand the concepts like execution context, scopes, lexical environment, hoisting, how Javascript behaves in different environments like Browser or Node.js, etc.

VAR

var is used to create a function scoped variable, that means it gets created when a functional block starts and can be accessed throughout it. Some key points to remember about var -

  • It is function scoped, it isn’t aware of blocks other than the function which declared it.

  • It can be redeclared.

  • It can be used before its declaration as it is hoisted.

LET/CONST

let and const are used to create a block scoped variable or constant, that means their access can be limited to a block not necessarily be a fucntion block. Some key points about let and const -

  • They were introduced in ES6, before that everything was declared with var.

  • They are block scoped, that means they respect every subsequent block that is defined inside a function or module.

  • They can’t be redeclared.

  • They can’t be used before declaration, that doesn’t imply that they are not hoisted. let and const do get hoisted but they reside in an area referred to as TDZ(Temporal Dead Zone).

LET vs CONST

let - defines a variable, it can be updated.

const - defines a constant, once assigned it can’t be changed.

Examples

Let’s look at some examples to understand above concepts -

(
    function() {
        var a = 10;
        if(true) { // block scope started
            var a = 20; // same variable
        }
        console.log(a);
    }
)(); // Output - 20

(
    function() {
        let a = 10;
        if(true) { // block scope started
            let a = 20; // new variable created for the block
        }
        console.log(a);
    }
)(); // Output - 10
(
    function() {
        var a = 10;
        var a = 20;
    }
)(); // Executes fine

(
    function() {
        let a = 10;
        let a = 20;
    }
)(); // Throws error - Identifier 'a' has already been declared
(
    function() {
        console.log(a);
        var a = 10;
    }
)(); // Output - undefined

(
    function() {
        console.log(a);
        let a = 10;
    }
)(); // Throws error - Cannot access 'a' before initialization
(
    function() {
        let a = 10;
        a = 20;
        console.log(a);
    }
)(); // Output - 20

(
    function() {
        const a = 10;
        a = 20;
        console.log(a);
    }
)(); // Throws error - Assignment to constant variable.

Browser vs Node environment

Javascript behaves differently in Browser and Node environment, let’s look at them one by one:

Node environment

In Node.js, a JS file is wrapped as a module. So variables defined globally in Node.js get bounded by a module and can be accessed inside that module but not outside it. They are not added to global scope(global variable) and is actually function scoped.

let a = 10;
var b = 20;
console.log(global.a);
console.log(global.b)

/* Output:
undefined
undefined
*/

Browser environment

Variables defined globally inside a script loaded in browser are truly global. They get added to the global scope. But var and let/const behave a bit differently. While they all lie in the same global scope, var gets added to the global object - window but let/const don’t.

let a = 10;
var b = 20;
console.log(window.a);
console.log(window.b)

/* Output:
undefined
20
*/

Scripts execute in the order in which they are embedded in HTML. So variables defined outside all functions in script files go to global scope and can be accessed across all the scripts.

<!DOCTYPE html>
<html lang="en">
<head>
    <script>
        let a = 10;
    </script>
    <script>
        console.log(a);
    </script>
</head>
<body></body>
</html>

/* console - 10 */

Finally, lets look at some problems paused by var(leading to use of let/const):

  • var doesn’t allow to declare a constant.

  • It can be accessed without initialization returning undefined.

  • It can be redeclared which may lead to accidental overwrites.

  • Doesn’t behave as expected with closures.

Example

for (var i = 0; i < 3; i++) {
  setTimeout(() => console.log(i), 100);
}
// Prints: 3, 3, 3

for (let i = 0; i < 3; i++) {
  setTimeout(() => console.log(i), 100);
}
// Prints: 0, 1, 2

In first example, var is the same in each iteration and doesn’t get redeclared, therefore, callbacks to setTimeout closes over the same variable which is at the end updated to 3. So, when executed all returns 3.

On the other hand, let forces it to get redeclared for each iteration, therefore, callbacks closes over different variables. So, when executed, prints their respective closure variables.

0
Subscribe to my newsletter

Read articles from Payal Rathee directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Payal Rathee
Payal Rathee