Block Scope & Shadowing in JavaScript

Block

Anything between two braces { } is called a block. It is also known as compound statement. A block is used to combine multiple JS statements into a single group. This allows us to have multiple statements in a place where JS expects a single statement.

if(i > 10) {

console.log("true");

i--;

}

In JavaScript, if statement expects a single statement. So, if we want to execute multiple lines of code within the if statement, we'll have to combine those statements into a single group by placing them inside a block.

Block Scope

Block scope refers to the functions and variables that can be accessed within a given block.

{

var a = 10;

const b = 20;

let c = 30;

console.log(a);

console.log(b);

console.log(c);

}

console.log(a);

console.log(b);

Output

10

20

30

10

Uncaught ReferenceError: b is not defined

From the above code, we can infer that let & const are block scoped, while var is not block scoped.

var is function scoped, i.e., var can be accessed anywhere in the lexical environment of the variable. Hence we cannot access let and const outside the block they're declared in.

let and const are not attached to the global object. Instead they are stored in a separate memory. But var gets attached to the global object.

Shadowing

When we have the same variable name in different places, the value of the variable closest to the line of execution is chosen. This phenomenon is called shadowing.

var a = 10;

const b = 20;

let c = 30;

{

var a = 100;

const b = 200;

let c = 300;

console.log(a);

console.log(b);

console.log(c);

}

console.log(a);

console.log(b);

console.log(c);

Output

100

200

300

100

20

30

The variables a, b and c inside the block are shadowing their counter parts having the same name outside the block.

But notice how in case of var, the shadowing is permanent.

This is because var is function scoped and gets attached to the global object. So a variable having the same name within a block and outside would point to the same location in the global object.

If we replace the block in the above code with a function, var behaves just like let and const.

var a = 10;

const b = 20;

let c = 30;

function x() {

var a = 100;

const b = 200;

let c = 300;

console.log(a);

console.log(b);

console.log(c);

}

x();

console.log(a);

console.log(b);

console.log(c);

Output

100

200

300

10

20

30

We don't see this in case of let and const as they're block scoped. JavaScript maintains a separate instance of them inside every block where they're declared.

Illegal Shadowing

The gist: while shadowing a variable, it should not cross the boundary of the scope.

#Illegal

let a = 10;

{

var a = 100;

}

Uncaught SyntaxError: Identifier 'a' has already been declared

This is illegal because var is not block scoped. So it put's JS in jeopardy whether to have 100 or 10 in the global space, and it can't just pick one. Also, in a particular scope, let cannot be re-declard. Hence the error.

#Legal

var a = 10;

{

let a = 100;

}

This is legal because let is block scoped. So outside the block JS doesn't have any other value other than 10 to choose from.

#Legal

let a = 10;

function x() {

var a = 100;

}

This is legal because var is function scoped. So JS once again has only one choice in the global space.