← all labs  ·  ← prev lab  ·  next lab →

Foundation Lab 08

The Global Object & Global Execution Context

Every JS program starts with one context that's created before anything else. Lab 05 showed it sits at the bottom of the call stack — this lab shows what it actually contains, and where your top-level declarations really end up.

What this lab produces: no files, no commit — a pure concept lab. You'll run one short snippet in a console or with node.
Concept type: Mostly JavaScript-Specific
▶
EXECUTION 10 of 10
◎
NAMES & SCOPE 2 of 10

This lab sits at the intersection of how the very first context comes into existence, and where the names declared inside it actually live.

Mental Models

The global context sits at the very bottom of the stack, always A stack of trays with the bottom one labeled global, marked as permanent and never removed. order #2 order #1 global — never removed

Mental Model 1 of 5Always at the Bottom, Never Popped

Top-level var and function declarations become properties of a real object A top-level var statement with an arrow pointing into a slot on a labeled object. var city globalThis .city

Mental Model 2 of 5var/function Attach to a Real Object

let and const skip the global object entirely A top-level let statement with an X where an arrow to the global object would be, and a separate private box instead. let country ✕ private record

Mental Model 3 of 5let/const Get a Private Home Instead

An analogy: a public lobby directory vs a private office A building lobby with a public directory board on one side, and a private office door with no listing on the other. LOBBY directory: Unit 4 - city private office (not listed)

Mental Model 4 of 5An Analogy: Lobby Directory vs Private Office

Misconception: the global object and the global scope are not the same thing A large circle labeled global scope, with a smaller circle inside it labeled global object, showing the object is only part of the scope. global scope (all top-level names) globalThis

Mental Model 5 of 5Misconception: "Global Object" ≠ "Global Scope"

Learning Objectives

  1. Objective 1 of 4 — I can explain why the global execution context is different from every other context on the call stack.
  2. Objective 2 of 4 — I can predict whether a given top-level declaration becomes a property of globalThis, based on which keyword declared it.
  3. Objective 3 of 4 — I can explain why let/const were designed to skip attaching to the global object.
  4. Objective 4 of 4 — I can demonstrate that two separate var declarations of the same name can silently collide, and explain why let/const don't fail the same way.

Pre-Lab Quiz

Answer from intuition first.

Question 1 of 5A top-level var city = "Toronto"; is declared. Is globalThis.city then equal to "Toronto"?Open question

Question 2 of 5A top-level let country = "Canada"; is declared instead. Is globalThis.country equal to "Canada"?Open question

Question 3 of 5In a plain (non-module) browser script, is this at the very top level the same object as globalThis?Open question

Question 4 of 5Two separate script tags on one page both declare var count = 0; at the top level. Do they silently share the same variable?Open question

Question 5 of 5Same scenario, but both script tags use let count = 0; instead. Same silent collision?Open question


The Concept

The global execution context is the foundation everything else sits on

Lab 05 introduced the call stack and mentioned the global context gets pushed first, before any of your code runs. This lab looks at what actually makes that first context special. Unlike every function-call context — created on demand, popped when the call returns — the global context is built exactly once, right at the start, and is never popped for as long as the program keeps running.

Why does a global object exist at all?

In JavaScript's earliest use as a browser scripting language, the engine needed some way to expose built-in browser features — things like alert, document, or setTimeout — as ordinary values a script could just use by name, with no import step required. The solution was to put them all as properties on one shared object. Once that object existed, it made sense to plug top-level var declarations and function declarations into the exact same object too, so your own top-level code and the browser's built-in features lived in one unified, lookup-by-name place.

var/function attach; let/const don't

Building directly on Lab 06's creation phase and Lab 07's TDZ model: during the global context's creation phase, every top-level var and function declaration is registered and attached as a property of the global object. Every top-level let/const is registered too — starting in the Temporal Dead Zone, exactly like inside any other block — but it's kept in a separate, private record that globalThis has no access to at all.

Cross-language note

Common concept: a place top-level names live.

Python: each module has its own namespace object, but there's no single shared object across every file the way globalThis is shared across every classic script on one page.

JavaScript: this whole "attach to a shared object" behavior is actually specific to classic, non-module scripts. A modern JS module (Lab 47 covers this) gets its own private top-level scope — nothing it declares attaches to globalThis at all, var included. Node.js goes even further: every file is automatically wrapped so top-level var doesn't leak onto the shared global object either.


Lab

Primary objective: confirm directly which top-level declarations attach to globalThis and which don't, and prove it's the same binding, not a copy.

You'll need: a browser console or node — no project, no files.

Lab 1 of 1 — Probe globalThis directly

Task

Declare a var and a let at the top level, and check both against globalThis.

Instructions

Step 1 of 4

// Paste this into node (not a browser console tab that already has other globals). Read it — do not run it yet.

var city = "Toronto";
let country = "Canada";

console.log("globalThis.city:", globalThis.city);
console.log("globalThis.country:", globalThis.country);

This step is complete when: you've predicted both log lines without running it.

Step 2 of 4

Predict both outputs, then reveal.

This step is complete when: you've run the snippet yourself and it matches the revealed output.

Step 3 of 4

// Edit the file yourself. Don't paste finished code — type it from these comments.

// After the existing code, reassign the property directly:
// globalThis.city = "Ottawa";

// Then log the plain variable "city" (not globalThis.city)
// to see whether it changed too.

This step is complete when: the new lines reassign globalThis.city and then log the bare city variable.

Step 4 of 4

Predict: after reassigning globalThis.city, does the plain variable city also change, or are they two separate copies of the value? Run it and compare, then answer this comprehension check: what does that result prove about the relationship between a top-level var and its property on globalThis?


Comprehension Checklist

  • I know the global execution context is created once and never popped, unlike every function-call context.
  • I can state which keyword (var/function vs let/const) causes a top-level declaration to attach to globalThis.
  • I know globalThis.city and the plain variable city are the same binding, not two separate copies.
  • I can explain why two classic scripts sharing a page can silently collide over a var name.

Post-Lab Quiz

These are different questions from the pre-lab quiz — they test what the experiment should have taught you, not the same questions again.

Question 1 of 5After running globalThis.city = "Ottawa";, does the plain variable city change too, or does it keep its original value?Open question

Question 2 of 5Why did globalThis.country come back as undefined in the experiment, even though country clearly has the value "Canada"?Open question

Question 3 of 5A function declaration (not var) is written at the top level. Does it also attach to globalThis, the same as var?Open question

Question 4 of 5Given this lab's model, what would you predict happens if you write globalThis.brandNewName = "hi"; with no matching var or let anywhere in the file?Open question

Question 5 of 5Would this lab's var/globalThis collision behavior still happen the same way inside a modern ES module file?Open question


Reflection Questions

Write your own answer first — the blurred text is one possible answer, not the only correct one.

Reflection 1 of 3. Before this lab, did you assume "global variable" and "property on the global object" were just two names for the same thing? How does that assumption break for let/const?

Reflection 2 of 3. Why might the designers of let/const have deliberately chosen to stop attaching to the global object, given how useful that attachment sounds?

Reflection 3 of 3. Predict: if you assign to a completely undeclared name without var/let/const at all (e.g. just brandNewName = "hi";) in non-strict mode, based on today's model, where do you think that name ends up?


What Breaks If This Understanding Is Wrong?

If you don't know top-level vars share one real object across every classic script on a page, a mysteriously overwritten variable from a completely unrelated file will look like a bizarre bug instead of a predictable naming collision — and you'll waste time looking in the wrong file entirely.

What JavaScript Concept Was Learned Today?

The global execution context is permanent and created first, and top-level var and function declarations attach as real properties on globalThis — while let/const stay off it entirely, even though both are equally "global."

Relates to: ▶ Execution (10 of 10) + ◎ Names & Scope (2 of 10) — how the very first context comes into being, and exactly where the names inside it end up.


Next

Lab 09 zooms out from "where do top-level names live" to the general question every scope, at every level of nesting, has to answer: when code references a name, how does JavaScript actually go looking for it? That search process is the scope chain.

← All labs  ·  Lab 09 — Lexical Environment & the Scope Chain →