Skip to content
Theory · Scope · lesson 1 of 8

Block scope

What you'll learn

What you'll learn:

  • tell where in a program a let, const or var variable is visible;
  • explain why a var above its line holds undefined, while a let there stops the program;
  • spot shadowing and understand whose variables a function sees;
  • turn on strict mode so that a typo in a name becomes an error.
A tinted-glass room { } holds a box let b; from inside you see var a in the corridor, but not the other way

Picture an apartment where every room has walls of tinted glass. From inside a room you can see the room itself and the hallway beyond the glass. But from the hallway you cannot look into the room.

A thing left in a room exists only for whoever is in that room. Variables in JavaScript work in a similar way: where a variable is declared is where it is visible.

But different declaration words have "rooms" of different sizes. Here one if branch declares two variables, and after the branch only one of them can be read:

JavaScript
function show(n) {
    if (n > 0) {
        var a = n;
        let b = n * 2;
        console.log(a, b); // 5 10
    }
    console.log(a); // 5
}

show(5);

Let's walk through what happens on the call show(5):

  1. The condition n > 0 is true, and execution enters the if branch.
  2. var a = n puts the number 5 into a, and let b = n * 2 puts the number 10 into b.
  3. Inside the branch both variables are visible, and the program prints 5 10.
  4. After the branch's closing brace, console.log(a) prints 5: the variable a outlived the branch.

If you put console.log(b) in place of the function's last line, the program stops with ReferenceError: b is not defined. The variable a is declared with var and b with let, and their visibility rules differ.

Blocks and scope

Scope is the part of a program where a variable's name can be read. A block is code in curly braces: an if branch, the body of a loop or a function. In our picture, a block is a room with glass walls.

Curly braces can also stand on their own, without if or for. Such a pair counts as a block too.

let and const live in a block

A variable declared with let or const is visible from its declaration line to the closing brace of its block:

  • it is visible in nested blocks, the way the hallway is visible from a room;
  • outside the block it does not exist;
  • at the block's closing brace it disappears.

So two neighboring blocks can hold two different variables with the same name:

JavaScript
const limit = 10;

{
    const half = limit / 2;
    if (half > 2) {
        console.log(half); // 5
    }
}

{
    const half = 1;
    console.log(half); // 1
}

Let's see who sees what:

  1. The constant limit is declared outside the blocks, so both blocks see it.
  2. The first half is visible in its block and in the nested if block, and the program prints 5.
  3. At the first closing brace the first half disappears.
  4. The second half is a different constant, and the program prints 1.

Here the room picture stops working. A real room stays there even when nobody is in it. A block, though, is created anew every time execution enters it, and it vanishes along with its variables at the closing brace.

var lives in the function

The word var is the old way to declare variables, and such a variable ignores blocks. It is visible in the whole function where it is declared, even after an if or a loop. This kind of scope is called function scope.

If a function is an apartment, a var variable stands not in a room but in the entrance hall: it is visible from any room of that apartment. Parameters follow the same rule: they are visible in the whole body of their function.

JavaScript
function lastSquare(n) {
    for (var i = 1; i <= n; i++) {
        var square = i * i;
    }
    return i + " " + square;
}

console.log(lastSquare(3)); // 4 9

Let's see where 4 9 comes from:

  1. The loop runs i from 1 to 3, and on the last pass square gets 9.
  2. Then i++ makes i equal to 4, the condition i <= n becomes false, and the loop ends.
  3. Both variables outlived the loop, so return builds the string 4 9.

If you replace both vars with let, the line with return stops the program with a ReferenceError. A var does not leave its function: outside lastSquare the names i and square do not exist.

Interviewers like to ask this: "What is the difference between var, let and const?" The answer has three parts:

  • var is visible in the whole function and ignores blocks;
  • let and const are visible only in their block;
  • a const variable cannot be assigned a new value.

New code uses let and const. var appears in old code, and you need to be able to read such code.

Common mistake

A variable is declared inside the branches of an if and read after them:

JavaScript
function label(n) {
    if (n > 0) {
        let sign = "plus";
    } else {
        let sign = "minus";
    }
    return sign; // ✗
}

console.log(label(5));
TEXT
ReferenceError: sign is not defined

Each sign lives only in its own branch, and by the line with return both are gone. To read the variable after the if, declare it before the if with let sign;, and assign to it in the branches: sign = "plus"; and sign = "minus";.

Key points

  • Scope is the part of a program where a variable's name can be read.
  • let and const are visible from their line to the block's closing brace, nested blocks included.
  • var ignores blocks and is visible in the whole function, but not outside it.
  • A variable needed after an if is declared before the if, and the branches only assign to it.

Subscribe to take the course

The course is free. Sign in with Telegram and subscribe to the channel to open every lesson.

Sign in another way