Scopes and Variable Shadowing in JS

If I give you the following example code:

const age = 30;

function func() {
const age = 31;
console.log(age);

for(let i = 0; i < 2; i++) {
const age = 32;
console.log(age);
}
}

func();
console.log(age);

What will be printed to the console?

Try to answer before you read on :) Self- testing is a great way of acquiring knowledge.

JavaScript is not terribly difficult but there’re nuances that are not always visible at the first glance.

What I want to demonstrate in the example above are scopes and variable shadowing.

There are 3 scopes in the example above — global, function, and block. JS has nowadays these 3 scopes. When I say scope, it basically means visibility — scope means where your declared variables will be visible.

For example, I can define a variable in a function:

function foo() {
const variable = 5;
}

I can use the variable name inside this function — the variable is visible inside this function. If I try to use the name outside, I’ll get .

On the other hand, if I try to declare the same variable again in the same scope, I’ll get telling me that the identifier is already declared.

Notice how I said “in the same scope” in the previous sentence. Because I can do the following:

const variable = 5;

function foo() {
const variable = 6;
}

And there’ll be no error at all.

This is where shadowing comes into play. inside the function shadows in the global scope in this example.

It also means that referring to inside the function will yield 6. Referring to in the global scope will yield 5.

Going back to the initial example, but with answers in comments:

const age = 30;

function func() {
const age = 31;
console.log(age); // 31

for(let i = 0; i < 2; i++) {
const age = 32;
console.log(age); // 32
}
}

func();
console.log(age); // 30

When run, it’ll produce this output:

31
32
32
30

One caveat with scopes might be when it comes to using the keyword when declaring variables. and are block scoped, which means that if I define variables with there keywords in a block, like in a loop, they will not leak outside the scope — I’d get if I try to access them outside the scope where they were declared.

But when it comes to , such variables are not block scoped; they can be function scoped.

An example might be better:

function foo() {
var a = 1;

for(let i = 0; i < 2; i++) {
var b = i;
}

console.log(b); // 1
}

foo();
console.log(a); // ReferenceError

Notice how leaked outside the block scope but did not leak outside the function scope.

This is typically unwanted and a bit surprising, that’s why and are used more in modern JavaScript. But it’s good to know about as well to be aware of this risk.

If you like my posts, please follow me. Thank you.

--

--

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store