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
▶
EXECUTION10 of 10
◎
NAMES & SCOPE2 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
Mental Model 1 of 5Always at the Bottom, Never Popped
Every other context (Lab 05) gets pushed and eventually popped. The global context is the one exception — it's built first, before anything else, and stays until the whole program ends.
Mental Model 2 of 5var/function Attach to a Real Object
A top-level var or function declaration doesn't just exist abstractly — it becomes an actual property on a real, inspectable object: globalThis.
Mental Model 3 of 5let/const Get a Private Home Instead
let/const are still registered during the global context's creation phase (Lab 06) — they just don't attach to globalThis the way var and functions do.
Mental Model 4 of 5An Analogy: Lobby Directory vs Private Office
A var at the top level is like a business listed on the building's public lobby directory — anyone in the building can look it up by name. A let/const is like a private office with no public listing — it's still a real place, just not something you can find by browsing the directory.
Mental Model 5 of 5Misconception: "Global Object" ≠ "Global Scope"
"Global scope" is the abstract idea of "every name reachable from the top level." globalThis is one specific, concrete object — only some of the names in global scope (the vars and function declarations) actually live on it.
Learning Objectives
Objective 1 of 4 — I can explain why the global execution context is different from every other context on the call stack.
Objective 2 of 4 — I can predict whether a given top-level declaration becomes a property of globalThis, based on which keyword declared it.
Objective 3 of 4 — I can explain why let/const were designed to skip attaching to the global object.
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.
globalThis.city: Toronto
globalThis.country: undefined
What you wrote: one var and one let, both at the top level,
then read both back through globalThis.
What the engine effectively does: during the creation phase, var
city registers AND attaches to the global object as a real property.
let country registers too, but into a separate, private record that
globalThis was never given access to -- so looking for it there
finds nothing, same as any other missing property (Lab 03).
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?
It's a very natural assumption, since for var they genuinely are the same
thing. The break happens with let/const: they're fully "global"
in the sense of being reachable from anywhere at the top level, but they never show up as
a property on globalThis — proving "global variable" and "property of the
global object" are related but not identical ideas.
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?
The same attachment that sounds useful is exactly what causes the silent collisions this
lab demonstrated — two unrelated pieces of code sharing one object by accident. Once
block scope existed as an alternative, keeping top-level names off a giant shared object
removed an entire category of naming-collision bugs, at the cost of losing the
"discoverable directory" convenience.
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?
It ends up exactly where globalThis.brandNewName = "hi" would put it — as a
new property on the global object — because in non-strict mode, assigning to an
undeclared name is treated as an implicit global assignment rather than an error. This is
widely considered a design mistake in the language, and is exactly the kind of accident
let/const's stricter rules (Lab 07) help prevent.
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.