Execution contexts
Understand the global execution context, creation and execution phases, variable environments, and how globalThis and top-level this differ in scripts and modules.
- 01Describe the global contextExplain the main workspace JavaScript creates before your file runs.
- 02Separate setup from runningPredict what creation phase prepares and what execution phase changes.
- 03Compare scripts and modulesTell when declarations become
globalThisproperties and what top-levelthisis.
Every run starts with a workspace
JavaScript does not run a file in empty space. Before the first visible line of code does real work, JavaScript creates an execution context: a workspace for the code that is about to run. This lesson uses a faithful mental model. The exact specification language comes much later in Execution contexts & jobs in the spec and Environment Records, and real engines optimize heavily behind this model.
A context keeps three ideas together: the variable names the code can use, a pointer to the outer scope to search next, and a this value. You already know variables, function locals versus outer variables, closures, and strict mode. Execution contexts connect those ideas to the moment code runs.
Imagine every job in an office gets its own desk. Before work starts, the desk gets a notepad listing the names that job may need, a note showing which room to ask next, and a label saying who this is for the job. Running code is the person at the desk filling in and changing that notepad.
- In real life: A desk prepared for a task
- In JavaScript: One execution context
- In real life: A notepad of names and values
- In JavaScript: The variable and lexical environments
- In real life: A doorway to the room outside
- In JavaScript: The outer scope reference
- In real life: A name tag that says who is in charge
- In JavaScript: The
thisbinding
Where the analogy stops: A real desk is a physical object. Engines are free to store or optimize values in many ways as long as JavaScript behaves as if these desks existed.
An execution context is the workspace JavaScript creates for the global script or for one function call: variables, an outer link, and a this value travel together.
The global execution context
MAIN OFFICEThe first context is the global execution context. Think of it as the main office for a script or module. Top-level code starts there, and functions declared at the top level are prepared there. When a function is called, JavaScript creates another context on top of the global one; when the function finishes, that context is removed. The Call stack lesson next explores that pushing and popping.
In browser classic scripts, the global context is connected to the global object, which browsers expose as window and all modern JavaScript exposes as globalThis. Do not confuse that object with the whole global environment: top-level let and const are global bindings in classic scripts, but they are not properties on globalThis.
A company may have one front office everyone can find. Some names are public at reception; other notes stay inside the office. A function call is like setting up a temporary desk for one visitor, then clearing it when the meeting ends.
- In real life: The building's front office
- In JavaScript: The global execution context
- In real life: A public directory at reception
- In JavaScript: Global object properties such as classic-script
var - In real life: Private notes in the office
- In JavaScript: Global lexical bindings from
letandconst - In real life: Temporary desks for visitors
- In JavaScript: Function execution contexts
Where the analogy stops: Modules get their own top-level scope, so the main-office metaphor changes: module declarations do not become public reception-desk properties.
function announce(label) { let message = label + " #" + count; console.log(message);} var status = "draft";let count = 1;count = count + 1;announce("Article");This code begins globally. The body of announce does not run when JavaScript first sees it. It runs only when line 9 calls the function, creating a fresh context with its own parameter and local variable.
Creation phase vs execution phase
STEP THROUGHEvery context has a setup part and a work part. During the creation phase, JavaScript prepares declarations. Function declarations are ready to call. var names exist with undefined. let and const names are known but uninitialized, which is why reading them too early throws a ReferenceError. During the execution phase, JavaScript runs statements line by line and changes values.
| Name | Where it is prepared | Creation phase | After execution |
|---|---|---|---|
| announce | function | ready to call | function announce |
| status | var | undefined | "draft" |
| count | let | uninitialized (TDZ) | 2 |
Step through the replay. The first frame is a teaching snapshot of creation-phase state; the later frames are recorded from real functions that compute and print the same output the displayed program prints.
First inspect the creation-phase snapshot. Then step through the execution phase and watch the function call add a new context.
script
let message = label + " #" + count; console.log(message);} var status = "draft";let count = 1;count = count + 1;announce("Article");The Hoisting & the temporal dead zone lesson goes deeper later. For now, keep the simple rule: declarations are set up before code runs, but only some are usable before their declaration line executes.
var versus letconsole.log(ready);var ready = "yes"; console.log(count);let count = 1;The tests run this as a real script. It logs undefined for the early var read, then throws a ReferenceError on the early let read.
- Function declaration becomes available before its line executes
var countexists withundefinedlet countis reserved but uninitializedcount = count + 1changes the stored valueconsole.log(message)prints- Calling a function pushes a new context
Sort each event by when it happens. Use the replay above if you are unsure.
Variable environments
CONCEPTUALYou will hear two related terms: variable environment and lexical environment. At this stage, use them as a careful mental model rather than spec vocabulary. var belongs to the function or global variable environment. let and const belong to lexical environments, including block scopes. A function call gets its own local environment and points to the outer environment where the function was created.
That outer pointer is the bridge to closures. In the Closures lesson, a function remembers the environment around it. Here, focus on the current call: JavaScript first checks the current context’s notepad, then follows the outer pointer if the name is not there.
const room = "global";function outer() { const room = "outer"; inner();}function inner() { const task = "inspect"; console.log(room, task);}outer();Global execution context
The main office exists first. Function names are available, and top-level constants will be initialized as their lines run.
| Idea | Simple meaning | Common declarations | Where it matters |
|---|---|---|---|
| Variable environment | The function/global area that old-style var uses | var | Function scope and classic global object behavior |
| Lexical environment | A scope record tied to where code is written | let, const, parameters, blocks | Block scope, TDZ, closures, shadowing |
| Outer reference | Where lookup goes next | A pointer, not a declaration | Closures and nested functions |
globalThis & this at the top level
INTERACTIVEglobalThis is the standard way to refer to the global object. In browsers, globalThis === window in ordinary same-window code. But top-level this depends on how the code is loaded. A classic sloppy script has top-level this equal to globalThis. An ES module has top-level this equal to undefined. Modules are strict by default, and their top-level declarations stay module-scoped.
var scriptVar = "var property";function scriptFunction() { return "function property";}let scriptLet = "lexical only";const scriptConst = "lexical only"; console.log(this === globalThis);console.log(globalThis.scriptVar);console.log(globalThis.scriptFunction());console.log(globalThis.scriptLet);console.log(globalThis.scriptConst);thisglobalThis in a sloppy classic scriptvar scriptVarcreates globalThis.scriptVarfunction scriptFunctioncreates globalThis.scriptFunctionlet / constglobal lexical bindings only, not propertiesClassic scripts are the old browser default. Top-level var and function declarations become global object properties; let and const do not.
vm scripts and module behavior with a real ES module import.| Place | Top-level or call this | Do declarations become global object properties? |
|---|---|---|
| Classic sloppy script | Top-level this is globalThis | Top-level var and functions do; let and const do not |
| ES module | Top-level this is undefined | No top-level declaration becomes a globalThis property |
| Plain function call, sloppy | this defaults to globalThis | Local var stays in the function |
| Plain function call, strict | this is undefined | Local var stays in the function |
var scriptVar = "var property";function scriptFunction() { return "function property";}let scriptLet = "lexical only";const scriptConst = "lexical only"; console.log(this === globalThis);console.log(globalThis.scriptVar);console.log(globalThis.scriptFunction());console.log(globalThis.scriptLet);console.log(globalThis.scriptConst);var moduleVar = "not a global property";let moduleLet = "module lexical";const moduleConst = "module lexical";function moduleFunction() { return "module function";} console.log(this === undefined);console.log(globalThis.moduleVar);console.log(globalThis.moduleFunction);console.log(typeof moduleLet);console.log(typeof moduleConst);Classic script: `var topic = "contexts";`Classic script: `function start() {}`Classic script: `let topic = "contexts";`Classic script: `const mode = "learn";`ES module: `var topic = "contexts";`ES module: `function start() {}`
Sort each declaration by what happens in a classic script or ES module.
Where you’ll use this
Execution contexts explain several bugs professionals see in real code. If a variable logs undefined before its assignment, you are seeing var creation. If a let read crashes before its declaration, you are seeing the temporal dead zone. If a helper accidentally writes to or depends on a global, it is really depending on the global context.
function scoreLabel(score) { var prefix = "Score"; return prefix + ": " + score;}console.log(scoreLabel(9));console.log(globalThis.prefix);This helper keeps prefix inside the function context. After the call, globalThis.prefix is still undefined. That is safer than relying on a global var that every script on the page can see.
Common misconceptions
“Creation phase runs my function body.”
It prepares a function declaration. The body runs only when the function is called during execution.
“Hoisting means declarations move in the file.”
The source code does not move. The context is prepared before execution, which can feel like declarations moved.
“Top-level variables are always on globalThis.”
Classic-script var and functions are; classic-script let and const are not. Modules do not add any top-level declarations as global properties.
“Top-level this is always the global object.”
That is true for sloppy classic scripts. It is false in ES modules, where top-level this is undefined.
“The replay is an engine debugger.”
It is a guided replay recorded from real JavaScript calls. It shows the values you need to learn the rule, not the engine’s private optimized memory layout.
Practice: trace the desk
5 EXERCISESvar readWhat does the first line print?
console.log(topic);
var topic = "contexts";The first line prints undefined. The name exists because of the creation phase, but the assignment to "contexts" has not executed yet.
Which declaration in the starter code does not become a global object property?
var scriptVar = "var property";
let scriptLet = "lexical only";
console.log(globalThis.scriptVar);
console.log(globalThis.scriptLet);scriptLet does not become a property. globalThis.scriptVar is "var property", but globalThis.scriptLet is undefined.
What does inner() print?
let label = "global";
function outer() {
let label = "outer";
inner();
}
function inner() {
console.log(label);
}
outer();It prints global. outer has its own label, but inner was declared globally, so its outer lookup finds the global label.
Move the shared-looking prefix into the function so it cannot collide with other scripts.
var prefix = "Score";
function scoreLabel(score) {
return prefix + ": " + score;
}function scoreLabel(score) {
const prefix = "Score";
return prefix + ": " + score;
}The fixed version creates prefix in the function context. It no longer adds or relies on a global property.
thisIn one word, what is top-level this inside an ES module?
Top-level this in an ES module is undefined. Use globalThis when you truly need the global object, and prefer module imports/exports for shared values.
Quiz: check your understanding
7 QUESTIONSPredict before you choose. Every answer explains the context rule it uses, so a wrong first guess still teaches you something.
Question 1 of 7What is an execution context in this lesson's mental model?
Choose an answer to see the explanation.
Question 2 of 7What does this classic script print before it throws?
Read the code, then predictconsole.log(topic); var topic = "contexts"; console.log(count); let count = 1;Choose an answer to see the explanation.
Question 3 of 7Which setup belongs to the creation phase?
Choose an answer to see the explanation.
Question 4 of 7In a classic script, which top-level declarations become
globalThisproperties?Choose an answer to see the explanation.
Question 5 of 7What is top-level
thisin an ES module?Choose an answer to see the explanation.
Question 6 of 7What does this program print?
Read the code, then predictlet word = "global"; function say() { let word = "local"; console.log(word); } say(); console.log(word);Choose an answer to see the explanation.
Question 7 of 7Why call this a faithful mental model instead of the exact engine implementation?
Choose an answer to see the explanation.
Key takeaways
- An execution context is a workspace for running global code or one function call.
- The global execution context is created first; function calls create additional contexts.
- Creation phase prepares declarations; execution phase runs statements and changes values.
varbelongs to function/global variable environments;letandconstuse lexical environments and have a TDZ.- Classic scripts and ES modules differ: module top-level
thisisundefined, and module declarations do not become global properties.
Execution context, one line.
A JavaScript execution context is the current workspace of bindings, outer scope, and this used while global code or a function call runs.
Up next: The call stack, where you will zoom in on how JavaScript pushes and pops these contexts as functions call each other.