Understanding Javascript Scope
Tags: javascript, tutorial
Published: 2019-10-14 04:38:14

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.

<b>Compilation and interpretation</b>

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](https://softwareengineering.stackexchange.com/questions/138521/is-javascript-interpreted-by-design) to get some understanding of it.

[This article](https://www.freecodecamp.org/news/javascript-essentials-why-you-should-know-how-the-engine-works-c2cc0d321553) has a good overview of the compiler/interpreter relationship in Javascript. 

I also recommend reading <a href='https://hackernoon.com/javascript-v8-engine-explained-3f940148d4ef' target='_blank'>this article</a> 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.

<b>Scope basics</b>

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:

{% gist https://gist.github.com/shadowwarior5/3fa93c5534c13a82f9931d0d5f21a13d %}

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

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

![Alt Text](https://thepracticaldev.s3.amazonaws.com/i/uc9875wit39ykhkxt12g.png)

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 <i>bar</i> variable there in the list. It's in the scope and it's still undefined.

2) Scope of <i>go</i> function. 

![Alt Text](https://thepracticaldev.s3.amazonaws.com/i/1efcu0mxbt824yt3g3qk.png)

Here we can see that actual scope that is different from the global scope. It has 2 declarations inside: a variable called <i>foo</i> and a function called <i>go_again</i>. We also have <i>this</i> 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 <i>goo</i> 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 <i>go_again</i> function

![Alt Text](https://thepracticaldev.s3.amazonaws.com/i/oweggdgey4pvip00u61p.png)

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

<b>let vs. var</b>

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

{% gist https://gist.github.com/shadowwarior5/32689f2110eb245c316b7670cce3ab8d %}

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](https://thepracticaldev.s3.amazonaws.com/i/tvefe01scjb5m2lnatmv.png)

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

![Alt Text](https://thepracticaldev.s3.amazonaws.com/i/8b0x7wf9dkszaehigsos.png)

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 <i>var</i> and <i>let</i> declarations are the way they are hoisted and initialized. You can learn more details from [this post](https://stackoverflow.com/questions/31219420/are-variables-declared-with-let-or-const-not-hoisted-in-es6) 

<b>Classic block scope problem</b>

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.

{% gist https://gist.github.com/shadowwarior5/9dc49a8122c7e4f0bb0b97fe14edc5b2 %}

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 <i>5 5 5 5 5</i>. At the point where we will print the variable <i>i</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 <i>var count</i> to <i>let count</i> inside the definition of <i>for</i> 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 - <i>0 1 2 3 4<i>.

<b>So, what we've learned?</b>

* 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 <i>var</i> are added to <i>function scope</i> and are accessible everywhere inside that function.

* Variables declared as <i>let</i> and <i>const</i> 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! :)