Execution Context, Control Flow
What is Execution Context?
Execution context is a fundamental concept in JavaScript that defines the environment where code is executed. Think of it as a container that stores:
- The code being executed
- The variables and functions available to that code
- The value of the
this
keyword - The outer environment reference (scope chain)
- Is essential for debugging and understanding call stack
- Hoisting behavior.
How Execution Context Works
Types of Execution Context
-
Global Execution Context (GEC)
- Created when JavaScript engine starts running your code
- Creates two important things:
- Global object (
window
in browsers,global
in Node.js) this
keyword (points to global object in non-strict mode)
- Global object (
- Serves as the base execution context
-
Function Execution Context (FEC)
- Created whenever a function is called
- Each function gets its own execution context
- Multiple FECs can exist during runtime
Execution Context Lifecycle
-
Creation Phase (Memory Creation)
- Creates the global object (for GEC)
- Sets up memory space for variables and functions
-
Execution Phase
- Executes code line by line
- Assigns actual values to variables
- Executes function calls (creating new execution contexts)
Example
let value1 = 20;let value2 = 30;
function addValues(val1, val2) { let sum = val1 + val2; return sum;}
let result_1 = addValues(value1, value2);let result_2 = addValues(6, 9);
JavaScript Execution Context ═══════════════════════════════════════
┌─────────────────────────────────────┐ │ Global Context │ ├─────────────────────────────────────┤ │ this: window │ └─────────────────┬───────────────────┘ │ ▼ ┌─────────────────┴────────────────┐ │ │ ▼ ▼ ┌────────────────────────┐ ┌───────────────────────┐ │ Memory Creation │ │ Execution Phase │ ├────────────────────────┤ ├───────────────────────┤ │ • value1: undefined │ │ • value1: 20 │ │ • value2: undefined │ │ • value2: 30 │ │ • addValues: fn() │ │ • result_1 ───┐ │ │ • result_1: undefined │ │ • result_2 ─┐ │ │ │ • result_2: undefined │ │ │ │ │ └────────────────────────┘ └─────────────┼─┼───────┘ │ │ ┌────────────────────────┐ │ │ │ Function Execution #1 │◄─────────────────────────┘ │ ├────────────────────────┤ │ │ Variable Environment: │ │ │ • val1: 20 │ │ │ • val2: 30 │ │ │ • sum: undefined │ ┌───────────────┘ │ │ │ │ Execution Thread: │ ▼ │ • sum = val1 + val2 │ ┌────────────────────────┐ │ • return sum (50) │ │ Function Execution #2 │ └────────────────────────┘ ├────────────────────────┤ │ Variable Environment: │ │ • val1: 6 │ │ • val2: 9 │ │ • sum: undefined │ │ │ │ Execution Thread: │ │ • sum = val1 + val2 │ │ • return sum (15) │ └────────────────────────┘
Control Flow
Control flow determines how JavaScript executes code from top to bottom. It includes various structures that alter this flow:
1. Sequential Flow
- Default execution order from top to bottom
- Each statement is executed one after another
let name = "John";let age = 30;console.log(name, age);
2. Conditional Flow
- Uses
if
,else if
,else
, andswitch
statements - Code execution based on conditions
if (age >= 18) { console.log("Adult");} else { console.log("Minor");}
switch (name) { case "John": console.log("Hello John!"); break; default: console.log("Hello stranger!");}
// `break` is used to stop the execution of the switch statement.// If there is no `break`, the execution will continue to the next case.// `default` is executed when none of the cases match.
3. Loop Flow
- Repeats code blocks using
for
,while
,do...while
- Continues until a condition is met
// For loopfor (let i = 0; i < 3; i++) { console.log(`Iteration ${i}`);}
// While looplet counter = 0;while (counter < 3) { console.log(`Count: ${counter}`); counter++;}
// `do...while` loop is similar to `while` loop, but it will execute the code block once before checking the condition.do { console.log(`Count: ${counter}`); counter++;} while (counter < 3); // `do...while` loop will execute the code block at least once.
4. Function Flow
- Functions create their own execution context
- Can alter flow through
return
statements - Includes function calls and callbacks
function processData(data, callback) { // Process data let result = data * 2;
// Alter flow with return if (!result) return null;
// Execute callback callback(result); // `callback` is a function that is passed as an argument to `processData`.}
5. Error Handling Flow
- Uses
try
,catch
, andfinally
blocks - Handles exceptions and errors gracefully
try { // Risky code throw new Error("Something went wrong");} catch (error) { console.error(error.message);} finally { console.log("Cleanup code");}
1. When no error occurs
try { console.log("try"); return; // returns undefined, but catch won't run} catch (error) { console.log("catch"); // this won't execute}
2. When error occurs
try { console.log("try"); throw new Error("oops"); // this causes catch to run return; // this line never executes} catch (error) { console.log("catch"); // this will execute return; // returns undefined}
3. If you want to run the catch block even if there is no error
try { console.log("try"); return true;} catch (error) { console.log("catch"); // this will execute return false;}
// the catch block is only executed when an exception is thrown in the try block. The presence or absence of a return statement (with or without a value) doesn't change this behavior.
try { console.log("try"); throw new Error("oops");} catch (error) { console.log("catch"); // this will execute}
Truthy and Falsy Values
- In JavaScript, certain values are considered “truthy” or “falsy” in conditional statements.
- Truthy values are values that are considered true in a boolean context.
- Falsy values are values that are considered false in a boolean context.
console.log(Boolean(0)); // falseconsole.log(Boolean(null)); // falseconsole.log(Boolean(undefined)); // falseconsole.log(Boolean("")); // falseconsole.log(Boolean(NaN)); // falseconsole.log(Boolean({})); // trueconsole.log(Boolean([])); // trueconsole.log(Boolean(function () {})); // trueconsole.log(Boolean(true)); // trueconsole.log(Boolean(false)); // falseconsole.log(Boolean("Hello")); // trueconsole.log(Boolean(" ")); // trueconsole.log(Boolean("0")); // true
Nullish Coalescing Operator
- The nullish coalescing operator (
??
) is a logical operator that returns its right operand when its left operand isnull
orundefined
, and otherwise returns its left operand. - When getting a value from an object, we can use the nullish coalescing operator to return a default value if the value is
null
orundefined
.
let value = null ?? "Default Value";console.log(value); // "Default Value"
Ternary Operator
- The ternary operator is a shorthand for an
if...else
statement.
const age = 20;const drink = age >= 18 ? "Beer" : "Juice";console.log(drink); // "Beer"
Break and Continue
- The
break
statement is used to terminate a loop or switch statement. - The
continue
statement is used to skip the rest of the current iteration of a loop.
for (let i = 0; i < 10; i++) { if (i === 5) break; // Terminate the loop when i is 5 console.log(i);} // output: 0 1 2 3 4
for (let i = 0; i < 10; i++) { if (i === 5) continue; // Skip the rest of the loop when i is 5 console.log(i);} // output: 0 1 2 3 4 6 7 8 9