DEV Community

Cover image for Understanding Javascript Scope
Konstantin Meiklyar
Konstantin Meiklyar

Posted on • Edited on

Understanding Javascript Scope

In the last 4 years, I interviewed around 100 javascript developers, experienced and not, for senior and junior positions. Many of them were good at what they are doing but were still missing knowledge of some very basic concepts that the language has. I can explain this by the fact, that many developers come and stay in javascript from other languages without taking time to learn some basics.

I did this mistake by myself several times when switching between languages and frameworks. It took me almost 10 years to realize how important is to learn the basics before diving into code.

In this post, I will cover a very basic JS concept called Scope. I will try to include everything you need to know about it in 5 minutes of reading.

This is my first tech blog post ever. I hope you'll have fun reading it and will be happy for any feedback.

Compilation and interpretation

One popular mistake about Javascript is thinking of Javascript as an "Interpreted language", that is not compiled. It's not exactly working this way. Javascript is not compiled to some "byte-code" similar to other languages, but there are definitely some processes happening before the execution of the code.

Most of major javascript engines (for example V8 used by in NodeJS and Chrome browser) are using JIT (Just-in-time) compilers. This is a very interesting topic and can require an additional blog post. I recommend reading this good old thread to get some understanding of it.

This article has a good overview of the compiler/interpreter relationship in Javascript. 

I also recommend reading this article explaining what V8 is and how it works.

So, for making things easier for now - let's say that when running JS code we have 2 phases - compilation phase and execution phase.

Scope basics

JS Scope is born during the compilation phase. Scope - is just something that tells the running code where to look for things. During that phase variables and functions are added to the scope for every function/block or on the global level. They still don't have any values. Values are something that comes to the scene only during the execution phase. Let's take a look on a piece of code:

Here we have 3 scopes: global scope and 2 function scopes - a scope of go and scope of go_again. Lets run this code and explore the scope using Chrome dev tools.

1) Global scope has a variable called bar and a function called go. If we will stop during the execution process on the first line we can see the scope in Sources tab in Google Chrome:

Alt Text

This is one more evidence that right now we are in the global scope and on the right side we have a long list of functions and variables that exist there. You can find bar variable there in the list. It's in the scope and it's still undefined.

2) Scope of go function.

Alt Text

Here we can see that actual scope that is different from the global scope. It has 2 declarations inside: a variable called foo and a function called go_again. We also have this inside this scope, I will ignore it for now as it's a topic for a whole separate post and I hope I will cover it there later.

The important thing here is goo variable that we see in the code but don't see in the scope of the function. The reason for that is the way it was declared. It has no initial declaration using var (or let and const that we will review later) keyword. In this case - during the compilation - it was not added to any scope.

The following will happen during the execution phase: The interpreter will look for the variable in local (function) scope - as we can see - it's not there, after that it will try to find it in parent/grandparent scope until it will get to the global scope. Global scope in default conditions will declare this variable and add it to the list of other variables declared on it.

3) Scope of go_again function

Alt Text

The thing worth mentioning here is that the value passed from parent function to go_again is declared in the local scope as well. Simple variables in JS are passed by value - so in this case - the local variable foo will be assigned to "xyz" while the original variable foo inside go function will keep the value of "def".

let vs. var

Since ES6 we have a new (well, not so new already) way to declare variables using let and const keywords. Declaring variables with let keyword has also effect on the scope - it creates a new type of scope - Block scope. Let's review a short piece of code using let and const in variables declaration.

As in the previous example - let's stop in debug mode during the execution and see how our scope looks like. Let's start with line #2:

Alt Text

We are now inside foo function and as we see inside our scope we don't have any variable excepting a and z variables. This is because rest of the variables here are declared using let keyword and exist only inside block scope of the block they appear in. Let's take a few more steps in the program and stop inside for loop:

Alt Text

So here, we see 3 new scopes added inside our function scopes. These are scopes of 3 blocks that we have inside our code.

One thing about the difference between var and let declarations are the way they are hoisted and initialized. You can learn more details from this post

Classic block scope problem

Since the release of ES6, there are few technical questions asked during the interviews that became classic problems related to function/block scope in JS. Let's review one of them briefly.

Having this code - what is the output of it? And how can we fix it to print the array in the right way?

So, the output of this loop will be 5 5 5 5 5. At the point where we will print the variable i that is set on the global level and not on block-level it will be changed to 5 globally.
You definetely understand at this point - that changing var count to let count inside the definition of for loop will change the scope of the variable to block level and will cause the loop to be printed in a way it was supposed to be - 0 1 2 3 4.

So, what we've learned?

  • Scope in JS is a place where declared variables and functions live.

  • The scope can be easily examined using Google Chrome dev tools.

  • Global variables are attached to the global scope and are accessible everywhere in the code. This is a bad practice and should be avoided, excepting some specific cases - mostly because for these variables the garbage collection is never done and can cause collisions with locally declared variables with the same names.

  • Variables declared as var are added to function scope and are accessible everywhere inside that function.

  • Variables declared as let and const are added to block scope and are accessible everywhere inside that block.

That's all for now!
Like and share if this post was useful for you.
Leave feedback if you have any.

And never lose your scope! :)

Top comments (2)

Collapse
 
jannikwempe profile image
Jannik Wempe

Great first post, congrats. Didn't know about how to inspect scopes in Chromes dev toolbar. This post exploained the concept of scopes really well, thanks :-)

One way to improve the post even more would be to make use of named anchor links instead of showing the full link in the post.

Collapse
 
shadowwarior5 profile image
Konstantin Meiklyar

Agreed, thanks for the feedback! :)