Deep dive JavaScript: Scope
Tags: javascript, webdev, beginners
Published: 2021-09-22 12:35:05

Are you always wondering how JS can understand our code, how scopes can be created? 

You'll need to have a better mental model about how JavaScript engine handles our code in general.  In this article, we are going through how JS scopes are created under the hood, step by step like:

- Compilation
- Parsing/Compilation phase
- Evidences of code compilation
- Briefly about lexical scope

## What is Compiled and Interpreted?

**Compilation** is a process that turns your code into a list of instructions that your machine can understand

**Interpretation** is similar to compilation but instead of processing the whole source code, it will be processed line by line. Each line is executed before proceeding to process the next line.  

Note: new JS engines actually use both compilation and interpretation to handle JS programs. 


## Step by step through compilation phase

JavaScript code is processed in **2 phases**: **Parsing/Compilation** and **Execution**

**Parsing/Compilation** phase will be our main concern in this article. 

Parsing/Compilation happens in 3 basic stages: 

- **Tokenizing/Lexing**: consider `var a = 7;` the program will likely to break this up into tokens: `var`  `a`  `=` `7` `;`
- **Parsing**: turn tokens into an Abstract Syntax Tree (AST)

```jsx
<VariableDeclaration>            var
	<Identifier>                  a
		<AssignmentExpression>    =
			<NumericLiteral>      7
```

  

- **Code generation**: take the AST and turn it into a set of instructions to actually create a variable called a and assign a value to it

Note: JS compilation only happens milliseconds right before the code is executed. 

## How do we know that compilation happens in 2 phases?

There are 3 cases that you can see that JS will handle your programs in at least 2 phases: parsing/compilation ⇒ execution

- Syntax errors
- Early errors
- Hoisting

  

### Case 1:

Consider: 

```jsx
const foo = 'cat'

console.log(foo)

const error = #7'dog' // Throw a syntax error here
```

If you run this code, you can observe that the program will throw the error first instead of logging `'cat'` to the console. 

This example shows that JS engine know about the syntax error on the third line before executing first and second line, by **parsing the entire program before executing it**. 

### Case 2:

Consider: 

```jsx
'use strict'

console.log('cat')

function saySomething(pet, pet) {
	console.log(pet)
}

saySomething('dog', 'fish') // Uncaught Syntax error: Duplicate param name not allowed
```

Again here, how can JS engine throw the error without logging `'cat'` to the console first? The answer is the code **must be fully parsed before any executions happen**. 

**Note**: duplicate param name is not allowed in strict mode, but it's allowed in non-strict mode. 

### Case 3:

Consider: 

```jsx
function myPet() {
	var dogName = 'Doggy';
	{
		dogName = 'Bata'; // error
		let dogName = 'Lucky'; 
		console.log(dogName)  
	}
}

myPet() 
// ReferenceError: Cannot access 'greeting' before
// initialization
```

Technically, the error is thrown because `dogName = 'Bata'` is accessing variable `dogName` before it's declared on the next line. 

But why it does not access the variable `var dogName` rather than accessing the `let dogName` ? 

*The only way JS engine would know is that:*

- JS processes the code first ⇒ comes to the statement `let dogName = 'Lucky'` ⇒ declare the a blocked-scope ⇒ set up all the scopes and their variable associations.

As you can see now: 

- JS code is parsed before any execution
- Scope is determined as the program is compiled, and will not change during run-time. 

## Lexical scope

If you declare a variable with `var` inside a function ⇒ the compiler handles this declaration as it's parsing the function ⇒ associates the variable with **function's scope** (*the variable is accessible anywhere inside the function*) .  

If you declare a variable with `let` or `const` ⇒ compiler handles this declaration ⇒ associates the variable with **block's scope (***variable is accessible inside the nearest {...} rather than its enclosing function***).** 

While scopes are identified during compilation, they're not actually created until runtime.

The scope of one variable, function or block cannot be changed later.

## Summary

Compilation is a set of steps that process the text of your code and turn it into a list of instructions that computer can understand. 

JS code is processed in 2 phases: **Parsing/Compilation and Execution** 

The Parsing/Compilation phase only happens in microseconds right before the code is executed

Scopes are identified during compilation

Lexical scope is controlled entirely by the place where functions, blocks, variables are declared

Thank you for your time.