JavaScript Crash Course; let keyword

Share this note with your friends.

Welcome to the JavaScript Crash course; let keyword. In this article, we will understand the basics of new 'let' keyword in ES6.

Important note: This post is the part of ES 6+ crash course / Modern JavaScript Refresher. Please click here to check other articles of the series.

The 'let' keyword was introduced in Java Script with ES 6, released in 2015. Like 'var', it is used to declare variables, but with some differences. Let’s first check the syntax:

let name1 [= value1] [, name2 [= value2]] [, ..., nameN [= valueN]];

If the syntax is not very clear to you, don’t worry, let’s check how the 'let' keyword is different from 'var' keyword:

We cannot redeclare variables defined with `let`.

We can redeclare variables defined with var. For example, in the following code, we are redeclaring (not redefining) the variable 'name'.

var name = "Kapil Sharma";
console.log("My name is " + name);

var name = 39;
console.log("My age is " + name);

Output:

node var1.js
My name is Kapil Sharma
My age is 39

However, we cannot redeclare the variable declared through `let` keyword.

let name = "Kapil Sharma";
console.log("My name is " + name);

let name = 39;
console.log("My age is " + name);

Running this example will cause an error:

node let1.js 
/home/kapil/dev/github/kapilsharma/ebooks/QuickNotesES6Plus/examples/ES6/let/let1.js:4
let name = 39;
    ^

SyntaxError: Identifier 'name' has already been declared
    at Object.compileFunction (node:vm:352:18)
    at wrapSafe (node:internal/modules/cjs/loader:1026:15)
    at Module._compile (node:internal/modules/cjs/loader:1061:27)
    at Object.Module._extensions..js (node:internal/modules/cjs/loader:1151:10)
    at Module.load (node:internal/modules/cjs/loader:975:32)
    at Function.Module._load (node:internal/modules/cjs/loader:822:12)
    at Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:77:12)
    at node:internal/main/run_main_module:17:47

Node.js v17.6.0

The reason is simple, redeclaring a variable in a program may cause unintended errors. Thus, ES6 does not allow it through 'let'.

In ES6 and later versions, it is highly recommended to use 'let' to declare variables, but not 'var'.

If you do not want the variable to be redefined as well, you may wish to use another new feature of ES6, 'const'

However, we may redefine the variables, for example:

let name = "Kapil Sharma";
console.log("My name is " + name);

name = 39;
console.log("My age is " + name);

Well, this is not recommended; You may not want to store age in a variable called `name` but if you decide to ignore naming conventions, or have weird naming conventions, ES6 will allow you. The output will be as expected:

node let1a.js 
My name is Kapil Sharma
My age is 39

Block scope

Before ES6 (2015), JavaScript had only Global Scope and Function Scope.

ES6 introduced 'let' and 'const' keywords in ES6 have block scope, that is, variables declared inside a { } block cannot be accessed from outside the block. Let’s see that through examples:

var x = 5;
console.log(x);

// Start a new block
{
    // Redeclare x and declare a new variable y;
    var x = 2;
    var y = 3;
    console.log(x);
    console.log(y);
}

// print it after the block
console.log(x);
console.log(y);

Output

node var2.js
5
2
3
2
3

As we can see, a variable declared inside the block (y) is available outside the block as well. Let’s try the same example with `let`.

let x = 5;
console.log(x);

// Start a new block
{
    // Redeclare x and declare a new variable y;
    let x = 2;
    let y = 3;
    console.log(x);
    console.log(y);
}

// print it after the block
console.log(x);
console.log(y);

Output

node let2.js 
5
2
3
5
/home/kapil/dev/github/kapilsharma/ebooks/QuickNotesES6Plus/examples/ES6/let/let2.js:15
console.log(y);
            ^

ReferenceError: y is not defined
    at Object.<anonymous> (/home/kapil/dev/github/kapilsharma/ebooks/QuickNotesES6Plus/examples/ES6/let/let2.js:15:13)
    at Module._compile (node:internal/modules/cjs/loader:1097:14)
    at Object.Module._extensions..js (node:internal/modules/cjs/loader:1151:10)
    at Module.load (node:internal/modules/cjs/loader:975:32)
    at Function.Module._load (node:internal/modules/cjs/loader:822:12)
    at Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:77:12)
    at node:internal/main/run_main_module:17:47

Node.js v17.6.0

As we can see in the output, the first three outputs are as expected. The output of the fourth log statement is `5`. That is, whatever we declared within the block, didn’t impact the variable declared outside the block.

Last log basically caused the error. It is because, we are trying to use the variable, declared within the block, outside the block, and it is not available outside the block.

Switch block

All the cases under a switch statement are a single block. It is a common mistake to consider different cases as separate blocks like:

let x = 1;
switch(x) {
    case 0:
        let foo;
        break;
    case 1:
        let foo; // SyntaxError for redeclaration.
        break;
}

In the above example, we will get an error on line 7, because we declared the same variable `foo` twice within the same block.

If we want different cases of the switch to be considered as a separate block, we must update our code as follow:

let x = 1;
switch(x) {
    case 0: {
        let foo;
        break;
    }
    case 1: {
        let foo;
        break;
    }
}

Now, this program will execute without any problem, although without any output, as we created separate blocks for each case/declaration of foo.

Temporal dead zone (TDZ)

The variables declared through 'let' are said to be in a 'temporal dead zone' (TDZ) from the start of the block until it is declared. Let’s understand it in more detail with an example:

console.log("Something outside block");

{ // TDZ begin for this block.
    console.log("Variable through var = " + var_var); //undefined
    console.log("Variable through let = " + let_var); // Reference error
    var var_var = 1;
    let let_var = 2; //End of TDZ for let_var
    console.log("Variable through var = " + var_var); // 1
    console.log("Variable through let = " + let_var); // 2
}

As shown in the above example, the Temporal dead zone for a variable is declared through 'let' the start as soon as a new block start. For `let_var`, TDZ starts at line 3 in the above example and ends at line 7. If it is referred during TDZ, as on line 5 of the above example, we will get the reference error as:

node tdz.js 
Something outside block
Variable through var = undefined
/home/kapil/dev/github/kapilsharma/ebooks/QuickNotesES6Plus/examples/ES6/let/tdz.js:5
    console.log("Variable through let = " + let_var); // Reference error
                                            ^

ReferenceError: Cannot access 'let_var' before initialization
    at Object.<anonymous> (/home/kapil/dev/github/kapilsharma/ebooks/QuickNotesES6Plus/examples/ES6/let/tdz.js:5:45)
    at Module._compile (node:internal/modules/cjs/loader:1097:14)
    at Object.Module._extensions..js (node:internal/modules/cjs/loader:1151:10)
    at Module.load (node:internal/modules/cjs/loader:975:32)
    at Function.Module._load (node:internal/modules/cjs/loader:822:12)
    at Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:77:12)
    at node:internal/main/run_main_module:17:47

Node.js v17.6.0

As we can see, the variable declared with `var` a simple print `undefined` and program execution continues. However, in the case of a variable declared through `let`, the program exits with an error.

At the first glance, new developers might think `var` is more beneficial as programs do not stop. However, when working on a larger project, we might want the program to throw errors for such human mistakes instead of solving a bad bug that is hidden in a large code and very difficult to find.

TDZ edge cases

It is highly recommended that we do not have the same variable name in a single program. Also, we should not be using variables declared through var. The following program demonstrates the reasons for this.

function testFunction(){
    var x = 1;
    if(x) {
       let x = (x + 2); // ReferenceError
    }
 }

 testFunction();

At a first glance, this program might look perfectly fine but we will get a reference error at line 4. Can you see why?

In line 2, we declared variable ‘x’. In line 3, for the if condition, TDZ is not yet started, as it will start after `{`. In the ‘if’ condition, the value of x is 1, and the condition passes.

In line 4, we are declaring x through let. Its TDZ started on line 3. In the same line, we are using `x + 2` but `x` is still in TDZ and hence we will get a reference error.

If we simply change line 4 variable name as `let y = (x + 2);`, the program will execute successfully.

Thus, regardless of TDZ, it is recommended not to use the same variable name twice in a program.

Next Topic

In this article, we discussed the `let` keyword. If you have any doubt, feel free to ask questions in the comments below or tweet your question by tagging @kapsnotes.

Leave a Comment