Javascript Variables: Scoping, Shadowing and Leaked Global

Samuel Nzekwe
6 min readApr 1, 2022

Its April 2022 and React 18 has just been released a few days before with improved functionalities and enhanced capabilities that have been made possible due to ‘concurrent rendering’.

I know, for a non coder or even someone who is just starting out early in their frontend programming journey, its very difficult to share in the excitement that most experienced programmers tend to always have about such release announcements and thats why i have started this 30 days series on Javascript and react. As a frontend engineer who is ever learning, i strongly believe in the old Picasso saying: ‘Learn the rules like a pro, so you can break them like an artist’.

Programming is 70% easier when you have an understanding of how the very basics fit together. No matter how complicated a software is, it is built from simple syntax structures like conditional statements, basic data structures, variables and loops. These structures are combined in numbers to create even the almost 2billion lines of code that now powers google!

This is 1 of 30 articles and in it, i would like to talk about variable scoping in javascript, shadowing and a very important and common source of bugs called leaked global.

Variables in Javascript:

In javascript, variables are considered as a very important component of the language as it provides means for our program to store data and retrieve data. Think of a variable like a label on a container that can contain any type of data from strings to numbers, lists and even boolean values.

In javascript we can declare a variable like this:

let nameOfVariable;      // variable declarationExample:
let name;

In the above, we declared a variable called “name”. Think of this like having a file folder that contains all the documents that belong to a friend of ours. As of now, we have only declared the variable( i.e, we have brought out an empty folder). Now, let’s assume that we then decide that all the documents belonging to our friend “Juliet” would be stored in this folder. To distinguish Juliets folder from that of Simon-since the folders look the same, lets add a name label ontop of the folder and assign Juliet's folder to Juliet and Simon’s own to Simon, like this:

let name = "Juliet"       //file 1- Variable assignment
customlabels.net

Note from the foregoing that variable declaration is different from variable assignment.

As mentioned earlier, all programs, even the most complex one are made up of variables and other smaller blocks of codes like conditional statements that enables our programs make decisions based on certain conditions that we provide. One of such conditional code blocks is the if-else conditional statement.

Let’s go back to our folder cabinet where we have kept the folder labelled Juliet. Upon opening the file cabinet, we realise that while we had gone for a walk, someone had unknowingly scattered our file arrangement in our cabinet of files. Now, to find Juliet’s folder, we will have to pick up each folder from the cabinet and check if the name on the folder is equal to ‘Juliet’.

To tell a computer to do this kind of sorting/searching, a part of our code instruction would like this:

1. let name = 'Juliet'      //declared and assigned2. if (name == 'Juliet') {
3. console.log('I found Juliet's file')
4. } else {
5. console.log('sorry! keep searching.')

Line 2 to 5 is called a code block. For a single program, there are usually many blocks of code within a single program file.

Local vs Global Scope

If we declare and assign our variable outside of a code block(like our name variable above), such a variable is considered to be in the global scope- not declared within any code block. Alternatively, if the variable is declared and assigned within a code block, then the variable is in the local scope- declared within a code block.

if (name == 'Juliet') {
let name = 'Michael' //Local scope
console.log('I found Juliet's file')
}

collectively, this is scoping. The idea of scoping at first glance is that we can not access variables that have been declared somewhere outside their scopes.

Shadowing and Leaked Global

Consider the code below

let score = 5 
let getMessage = function () {
let score = 2
return `Score: ${score}` //Accessing score value
}
let result = getMessage()
console.log(result)
console.log(score)

score has been declared and assigned in two different places, which of the score values do you think our program will 1) return and 2) console out ?

Certainly, both variables have been declared in two different scopes. The score = 5 has been declared as a global variable, while the score = 2 has been declared as a local variable within the function getMessage(). Inside getMessage(), score would have a value of 2 but outside that block, the value of score will be 5. Easy! Inside a local scope, local variables take precedence over global variables and this is what is known as Shadowing.

Going forward, take time to consider the code below:

let name = “Juliet”
if (true) {
if (true) {
console.log(name)
}
}
console.log(name)

What do you think each of the above console statements will print to the screen? ‘Juliet’. Here is the explanation: When python starts from the inner code block, it looks within that local scope for a variable ‘name’ and since we did not declare and assign any of such variable in the scope, javascript moves out of the scope into the next higher parent scope, which is the outer if-block and again, looks for the ‘name’ variable there, we did not also define a name variable in the local scope of this surrounding higher code block and again, javascript moves further outwards into the global scope where we have declared the name variable and assigned it a value of ‘Juliet’, this is the value that the inner console statement will print, same as the outer console statement.

If at this point all of this still makes sense, try to think of what would be the result of each console statement in the code below:


if (true) {
console.log(name) // 3 if (true) {
name = 'Doris'
console.log(name) // 1
}
}
console.log(name) // 2

What would console 1 and 2 print out?

Notice that there is no explicit definition of a variable in the above code snippet, all we did was re-assign a value to a ‘name’ variable. Also notice that we did not declare nor assign any variable even in our global scope, however when we run that code, we see that even console 2 prints ‘Doris’. If we add a third console statement for name within the local scope of the outer parent block, we will still get ‘Doris’ as a value.

We can understand that line 1 prints ‘Doris’, but why line 2 and line 3?

The answer is what is called Leaked Global in Javascript and is one of the leading sources of logical errors and syntax errors in javascript. Whenever we assign a variable in a local variable without explicitly declaring it with the ‘let’ keyword, and then try to access that assigned variable from anywhere else outside the local scope, javascript always automatically declares it as a global scope variable and as such it can be accessed from within any block.

To avoid this, always ensure to declare and assign all local scope variables before they leak into the global scope and cause errors that cause you to pay significant amounts in time currency.

--

--

Samuel Nzekwe

Once i studied Physics and enjoyed being an on air personality, now i’m a software engineer who enjoys writing about codes and great digital products.