Scopes in JavaScript
Tags: javascript, webdev
Published: 2021-01-04 19:21:22

## Introduction

**Scope**: maybe you read a hundred of times the word when reading an article about JS or a post on Stackoverflow. 
> But what does *scope* actually means in JavaScript and how scopes are managed?

Let's dive into this in the following sections. :) 

### What is scope?

Our program has states. Without this, to be honest, our code would just perform operations, do some API calls or calculate things, etc. But it you want to store these results somewhere, you need variables. 

These variables later can be retrieved, updated and it enables more powerful ways to build applications. But how can you access and for what variables you have access to when a piece of code is running?

These questions need to be answered with a well defined set of rules that manages the access to variables.

> The *scope* is a set of rules that manage the accessibility of variables.

## Type of scopes

There are two *main* type of scopes that can be divided into smaller pieces.
 
* *Global* scope
* *Local* scope

### Global scope

Global scope is the most outer scope of the existing scopes. Variables created in the global scope can be accessed within any scope.

Any variables declared on the global scope is called a *global* variable. Although, it is not a good idea to pollute the global scope with variables. 

Because any block of code has access to the global variable set, collisions can happen easily which may overwrite or update the values stored in that global variable accidentally.

To avoid this problem, let me introduce the *local* scope which is helpful in these cases.

### Local scope

Variables and constants declared within any kind of *block* is somewhat local scoped and does not pollute the global environment. 
These can be created with *{}* braces but do not let the chance of understanding slip away and be more precise than this. 
In the following sections we will walk through the types of *local* scopes.

#### Function scope - var & let & const

> Create scope for var, let and const

If you think about how can you create a scope for your variables, maybe it comes to your mind that a function can come in handy. 
Functions in JavaScript create a new scope called *function scope*. 
The another useful tool of function scopes is closures but it is a good theme for another post. :) 

An example for the better understanding.

```
function _fscope() {
  let a = 1;
  console.log(a); // outputs: 1
}
console.log(a); // ReferenceError: a is not defined

globalThis.a // evaluates to undefined
```

As you can see, a simple function declaration creates a scope for the variables declared within it. You can not access to that variable outside of that *scope*.
An [IIFE](https://developer.mozilla.org/en-US/docs/Glossary/IIFE) creates a scope as well as basic function declarations.

#### Block scope - let & const

> Create scope for let and const

A block scope now is really can be described as a scope within *{}* curly braces or another way: a JavaScript block of code defines a scope for variables.

The following example can give a quick view of its behavior.

```
{
  let q = 123;
  console.log(q); // 123
}
console.log(q); // ReferenceError: q is not defined

globalThis.q // evaluates to undefined
```

This is really the simplest example. The following *blocks* create *block scope* for variables.

* Loops
* Conditional statements 'body'
* A simple {} block

**Nesting scopes**

Scopes can be nested, which means: any of the 'inner' scope has access to the containing scopes up to the global object. Or if you start from the other end of the statement, none of the 'outer' scopes has access to the 'inner' scopes. It shouts for an example!

```
const global = '2021';
(function() {
	let outer = 123;
  if (outer) {
    const inner = 'inner';
    console.log(global, inner, outer); // '2021' 'inner' 123
  };
    console.log(global, inner, outer); // ReferenceError: inner is not defined
})();
```

As you can see in the above example, a nested scope has access to all of the outer scopes, but a scope does not have access to its inner ones.

#### Module scope

ES2015, or maybe you known it as ES6 introduces *modules*. Modules are just a simple *.js* or *.mjs* file. It does not matter is a module is CommonJS module or an ES6 module, it creates a scope for:

* Functions
* Classes
* Variables

So unless you not export one of the above mentioned member of the module, it is not available in another module, even if you import that module. It is a good separation mechanism.

### The +1: **var**

As you see above, only the function scope can encapsulate a variable created with *var* (and this is +1 reason why using var is not recommended nowadays).

Sometimes I find debates whether *var* creates variables on the global scope. Let revisit this part os JavaScript.

> Creating variables with *var* **not** creates variable on the global scope. 

Variables created with *var* is **function scoped**, so the following will output *undefined*:

```
(function (){
    var q = 3;
})();
console.log(globalThis.q);
*undefined*
```

But the following will output a not so nice thing

```
if(true) {
  let a = 3;
  var b = 2;
}
console.log(globalThis.a); // undefined
console.log(globalThis.b); // 2 - oops :( 
```

My recommendation: try to use let everywhere except there is a very-very strong reason for using var.

The related article can be found on the official [Docs](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/var) 

## Conclusion

Understanding scopes is an important part in the long learning path of JavaScript, but definitely can helps reduce debug time and gives a better understand of how the JS codes working.

I hope you enjoyed my article, please add your comments below! :) 

@Cover image: [Unsplash](https://unsplash.com/@simonmaage)