JavaScript Basics-  Scopes & Hoisting
Tags: javascript, tutorial, webdev, beginners
Published: 2021-04-12 09:04:57

If you're a JS beginner, you must have heard these words.

Let's get in depth to understand more about these concepts in JS.

## What is a Scope in JS?

A scope in JS is a context in which values and expressions are ***visible*** or can be referenced.
In simple words, Scope is the accessibility of variables, functions, and objects in some particular part of your code during runtime. 

### Types of scopes in JS:

JavaScript has 3 types of scopes :

 * Global Scope : Any variable, function, expression that is present globally or not declared inside any other function belongs to the global scope. Variables, functions that declared in global scope can accessed from anywhere in the program.

```
var foo=23; // declared in the global scope

function greet(){
console.log(foo);
} 

greet();// Prints '23'
console.log(foo)l //Prints '23'
```
* Local or Function Scope : Variables and functions  that are enclosed in some other function become part of that function's local or function Scope. In other words, a local scope or function scope is associated with a function, when we declare variables and functions inside ***another function***, they become part of the local/function scope and are ***restricted*** to that scope. Variables and function declared in function/local scope are ***accessible within that scope***.

```
//Declared in Global Scope
var foo=23;
 
function bar(){ 
// Function or Local Scope
   var message="Hello JavaScript"; // inside the local/function 
                                   scope of bar 
   console.log(message); // Prints 'Hello JavaScript' 
   console.log(foo); // Prints '23'
}

//Global Scope
console.log(message); // Uncaught ReferenceError: message is not 
                         defined

```

* Block Scope : Variables declared with let and const can block scoped. That is, they can be enclosed within a pair of curly braces(***blocks***). Any variable/function declared with let or const, inside a pair of curly braces are only available within the scope of the braces. It stands true for only for variables that declared with ***let and const*** and not with ***var***.

```
{ //Block scope
  let message = 'Hello JavaScript'; // declared with let
  var name = 'Debarshi'; // declared with var
  console.log(message); // Prints 'Hello JavaScript'
}

//Global scope
console.log(name);// prints 'Debarshi'
console.log(message); // Uncaught ReferenceError: message is not 
                         defined
```


## Hoisting in JS:

In JavaScript, ***hoisting*** is a concept in which a function or a variable can be used before declaration.

### Hoisting with variables and functions declared with var keyword.

Variables declared with var keyword gets hoisted to the top of the scope. If accessed before **initialization** they result ***undefined***.

```
console.log(baz); // Prints 'undefined'

console.log(greet); // Prints 'undefined

greet(); // Prints 'TypeError: greet is not a function'

var baz="Hello World!";

//anonymous function stored in a variable
var greet=function(){
    console.log("Hello JavaScript!");
}

greet(); // Prints 'Hello from JavaScript!'
```


## Hoisting with variables and functions declared/assigned with **let** and **const** keyword

Although variables and functions declared/assigned to ***let*** and ***const*** are also hoisted, but they cannot be accessed until they have been ***initialized***.


```
console.log(a); // Prints 'ReferenceError: Cannot access 'a' 
                    before initialization'
console.log(name); // Prints 'ReferenceError: Cannot access 'm' 
                       before initialization'

doSomething(); // Prints 'ReferenceError: Cannot access 'm' before 
                   initialization' 

let a = 45; // Initialized
const name="Debarshi"; // Initialized

const doSomething = function (){
   console.log("Hello World!")
}

console.log(a) // Prints '45'

console.log(name) // Prints 'Debarshi'

doSomething(); // Prints 'Hello World!'
```

### Hoisting with functions:
<br/>

  * Functions declared with ***function*** keyword:
    Functions that are declared with the ***function*** keyword 
    are also hoisted and can accessed from the top of the scope.
   

     ```
       foo(); // Prints 'Hello from foo!'
       
       function foo(){
          console.log("Hello from foo!");
        } 
     ```
<br/>

  * Anonymous functions, functions expression:

     As anonymous functions and function expressions are 
     assigned/stored to a ***variable***, they behave same as 
     that of the variable ***depending on the variable type they 
     are assigned to***.


     ```
       baz(); // TypeError: baz is not a function
       foo();  // Uncaught ReferenceError: Cannot access 'foo' 
                  before initialization

       var baz=function(){ // assigned to var
       console.log("Hello from Baz");
       }

      let foo=()=>{  assigned to let
       console.log("Hello from Foo");
      }

      baz(); // Prints 'Hello from Baz'
      foo(); // Prints 'Hello from Foo'
     ```

### Temporal Dead Zone in JS:
        
 let and const variables cannot be read/written until they 
 have been fully initialized, which happens when they are 
 declared (if no initial value is specified on declaration, 
 the variable is initialized with a value of undefined). 
  Accessing the variable before the initialization results in 
  a ReferenceError.

      { // TDZ starts at beginning of scope
      console.log(bar); // undefined
      console.log(foo); // ReferenceError
      var bar = 1;
      let foo = 2; // End of TDZ (for foo)
     }
     
### References:

[MDN]("https://developer.mozilla.org/en-US/docs/Glossary/Hoisting")