# JavaScript Lexical Scope and Compilation

*Part 2 of the JavaScript Deep Dive Series*

Before JavaScript executes a single line of your code, something crucial happens behind the scenes. While most developers think JavaScript executes and runs code line by line(I know I mentioned this in the first series), the reality is more sophisticated and understanding this process is the key to mastering scope, hoisting, and variable behavior. Javascript still executes code line by line, but before that it interprets/compiles the javascript code.  
When you write a javascript code, the first thing that happens is what I refer to as “Parsing” also can be referred to as “Compilation” or interpretation.  
  
A relatable example is when you have a syntax error in your code on line 20, but immediately you recompile, you get an error, when infact your code hasn’t executed up to line 20, the reason why this error shows up immediately is because of the first step “Parsing/Compilation”, during this phase, Javascript engines runs through the code, define variables, verify syntaxes, etc.  
  
So, your code is first compiled, then executed, and that brings us to “The Two step process”.

## JavaScript's Two-Step Process

Javascript follows a **two-step process**:

1. **Compilation Phase** - JavaScript scans through your entire code, setting up scope and preparing for execution
    
2. **Execution Phase** - The actual running of your code, line by line
    

## This compilation step is where all the "magic" of **hoisting**, **scope creation**, and variable declarations happens.  
  
**Definitions**

Before we proceed into JavaScript's compilation process, let's explain a few terms you will come accross:

**Scope** - The accessibility of variables and functions in different parts of your code. It determines where you can use a particular variable.

**Lexical Scope** - Scope that is determined by where variables and functions are declared in your code (at write-time), not where they are called from (at runtime).

**Global Scope** - The outermost scope in JavaScript. Variables declared here are accessible from anywhere in your program(more like in the window).

**Function Scope** - A scope created inside a function. Variables declared here are only accessible within that function.

**Block Scope** - A scope created by curly braces `{}` when used with `let` or `const`. Variables declared here are only accessible within that block.

**Source Reference** - When a variable is being read or accessed (appears on the right-hand side of an assignment or in expressions like `console.log(variable)`).

**Target Reference** - When a variable is being assigned a value (appears on the left-hand side of an assignment like `variable = "value"`).

**Compilation Phase** - The first step where JavaScript scans through your code, sets up scope, and prepares variable declarations before any code executes.

**Execution Phase** - The second step where JavaScript actually runs your code line by line.

**Scope Chain** - The hierarchy of scopes that JavaScript searches through when looking up a variable, starting from the innermost scope and moving outward.

**Hoisting** - The behavior where variable and function declarations are processed during the compilation phase, making them available throughout their scope even before their declaration line is reached during execution.

### Step 1: Compilation - The Setup Phase

During compilation, JavaScript's engine acts like an organizer, scanning through your code and asking two critical questions about every variable it encounters:

**"What scope does this belong to?"**  
**"Is this a source or target reference?"**

```javascript
var teacher = "Kyle";

function otherClass() {
    teacher = "Suzy";
    topic = "React";
    console.log("Welcome!");
}

otherClass();
```

Let's trace through the compilation phase:

**Line 1:** `var teacher = "Kyle"`

* Compiler finds `teacher` declaration
    
* Creates `teacher` in **global scope**
    
* Notes: This will be a **target reference** (receiving a value)
    

**Line 3:** `function otherClass()`

* Compiler creates `otherClass` function in **global scope**
    
* Creates **new scope** for inside the function
    

**Line 4:** `teacher = "Suzy"`

* Compiler sees `teacher` reference
    
* No declaration here, so it's a **source reference** (looking up existing variable)
    
* Notes: Will look up scope chain during execution
    

**Line 5:** `topic = "React"`

* Compiler sees `topic` reference
    
* No declaration anywhere - this will create an **implicit global**
    

## Source vs Target References

Understanding the difference between source and target references is crucial:

**Target Reference** = **Left-hand side** of assignment (receiving a value)

```javascript
var student = "Frank";    // student is TARGET
teacher = "Kyle";         // teacher is TARGET
```

**Source Reference** = **Right-hand side** of assignment (providing a value)

```javascript
console.log(teacher);     // teacher is SOURCE
var message = teacher;    // teacher is SOURCE, message is TARGET
```

### Why This Matters

The engine handles source and target references completely differently:

**Target references:** Must have a declared variable to assign to **Source references:** Must find an existing variable to read from

```javascript
// Compilation phase creates these declarations
var teacher;              // TARGET reference prepared
var student;              // TARGET reference prepared

// Execution phase
teacher = "Kyle";         // TARGET - assigns to existing declaration
console.log(teacher);     // SOURCE - looks up existing value
topic = "React";          // TARGET - no declaration found, creates global
console.log(subject);     // SOURCE - no declaration found, ReferenceError!
```

## Lexical Scope - Where You Write Matters

**Lexical scope** means scope is determined by **where you write your code**, not where you call it. The physical placement of your variables and functions determines their scope relationships.

```javascript
var teacher = "Kyle";

function otherClass() {
    var teacher = "Suzy";
    
    function ask() {
        console.log(teacher);  // Which teacher?
    }
    
    ask();
}

otherClass(); // "Suzy"
```

The `ask()` function looks for `teacher` in this order:

1. **Local scope** (inside `ask`) - not found
    
2. **Enclosing scope** (inside `otherClass`) - found "Suzy"!
    
3. **Global scope** - never reaches here
    

This lookup happens **at compile time** based on where you wrote the code, not where you called it.

## Scope Chain Resolution

JavaScript creates a **scope chain** during compilation - a linked list of scopes from innermost to outermost:

```javascript
var global = "I'm global";

function outer() {
    var outerVar = "I'm in outer";
    
    function inner() {
        var innerVar = "I'm in inner";
        console.log(innerVar);  // Found in inner scope
        console.log(outerVar);  // Found in outer scope  
        console.log(global);    // Found in global scope
        console.log(missing);   // ReferenceError!
    }
    
    inner();
}

outer();
```

**Scope chain for** `inner()` function: Inner Scope → Outer Scope → Global Scope

The engine walks up this chain until it finds the variable or reaches the end (ReferenceError).

## The Compilation Process in Action

Let's trace through a complete example:

```javascript
console.log(teacher);        // What happens here?

var teacher = "Kyle";

function ask() {
    console.log(teacher);
}

ask();
```

**Compilation Phase:**

1. Line 3: Create `teacher` declaration in global scope
    
2. Line 5: Create `ask` function in global scope
    
3. Line 6: Create new scope for `ask` function
    
4. All source references noted for execution phase
    

**Execution Phase:**

1. Line 1: `console.log(teacher)` - SOURCE reference to `teacher`
    
    * `teacher` exists (from compilation) but value is `undefined`
        
    * Output: `undefined`
        
2. Line 3: `teacher = "Kyle"` - TARGET reference
    
    * Assigns "Kyle" to existing `teacher` declaration
        
3. Line 8: `ask()` - Calls function
    
4. Line 6: `console.log(teacher)` - SOURCE reference
    
    * Looks up `teacher` in scope chain, finds "Kyle"
        
    * Output: "Kyle"
        

## Common Scope Misconceptions

**"Hoisting moves declarations to the top"** False. Nothing physically moves. Compilation creates declarations before execution begins.

**"let and const aren't hoisted"**  
False. They are hoisted but in a "temporal dead zone" until their line is reached.

**"Functions create scope"** Partially true. Function declarations create scope, but so do blocks with `let`/`const`.

**"Scope is determined at runtime"** False. Lexical scope is determined at compile time by where you write code.

## Practical Applications

Understanding compilation and lexical scope helps you:

**Debug Variable Access Issues**

```javascript
function broken() {
    console.log(name);  // ReferenceError - not undefined!
    let name = "Frank";
}
```

**Predict Hoisting Behavior**

```javascript
console.log(typeof teacher);  // "undefined" (var hoisting)
console.log(typeof student);  // ReferenceError (let in TDZ)

var teacher = "Kyle";
let student = "Frank";
```

**Understand Closure Creation**

```javascript
function makeCounter() {
    var count = 0;
    return function() {
        return ++count;  // Lexical scope preserves access to count
    };
}
```
