The browser environment
Learn how JavaScript meets the browser: window, globalThis, the DOM, browser environment objects, web standards, and the different places scripts can run.
- 01What the browser addsTell the JavaScript language (ECMAScript) apart from the tools the browser adds, such as
window,document,location, timers, andfetch. - 02Which names go on windowPredict which top-level names become properties on
window, and why modules work differently. - 03Where code runsCompare page scripts, module scripts, workers, and Node.js, and say which global names each one has.
JavaScript inside a browser
You already know a lot of JavaScript: values, functions, objects, scope, classes, errors, and code that waits. Stage 7 adds something new. Your code now runs inside a host. A host is the program that runs JavaScript and adds its own extra tools. Here, the host is the web browser.
The browser gives your code objects that are not part of the language itself. These objects make web pages possible. For example, document lets you read and change the page.
This lesson answers five questions:
- What is
window? - Why does
documentexist? - What do people mean by "BOM"?
- Which written standards describe these objects?
- Why don't a page script, a module script, a worker, and Node.js all have the same global names?
The official name for the rules of the JavaScript language is ECMAScript. The browser environment is ECMAScript running inside a web browser, plus the extra tools the browser adds. The browser adds tools for the page, the web address, facts about the device, timers, pop-up dialogs, network requests, and more.
const price = 3;
const total = price * 2;
console.log(total);Line 1 stores the number 3 in price. Line 2 multiplies it by 2. Line 3 prints 6. This code needs no page, no web address, and no browser window. So it runs the same way in a browser, in Node.js, or in a test runner.
A car engine can turn, but it can't steer on its own. It has no dashboard and no radio. The car around the engine adds those parts, so a driver can use it.
- In real life: The engine
- In JavaScript: The JavaScript engine, which runs the language
- In real life: The wheels and steering
- In JavaScript: The DOM: read and change the page
- In real life: The dashboard
- In JavaScript:
location,history,navigator, andscreen - In real life: The radio and other gadgets
- In JavaScript: Timers,
fetch, the console, and other host tools
Two earlier lessons cover the background: Engines, runtimes & hosts and Manuals & specifications. This lesson is about the browser tools you will use in every lesson about the page that comes next.
window as the global object
INTERACTIVEIn a page script, the browser gives you a big object called window. It is the global object: the object where JavaScript looks for global names. That is why you can write alert("Hi") instead of window.alert("Hi"). Your code has no variable called alert, so JavaScript looks on window and finds it there.
A classic script is a normal <script> tag, without type="module". A top-level name is one made outside every function and block. In a classic script, top-level names work in two different ways:
- Top-level
varand top-level function declarations become properties onwindow. You saw this in thevarand the global object lesson. - Top-level
let,const, andclassmake global names too, but they are not properties onwindow. The browser keeps them in a separate list of global names.
Other classic scripts on the same page can still use those let names. They just can't reach them through window.
var puts the name on window. Top-level let makes a global name too, but keeps it off window.Step through one classic script. Watch the difference between a global name and a property on the global object.
script
function greet() { return "hello from a classic script";}console.log("fruit" in globalThis);console.log(globalThis.fruit);console.log(typeof greet);Now let a real page answer the same question. The explorer below runs fixed code inside an iframe, a small page inside this page. The iframe is sandboxed: its permissions are locked down. It sends its results to this page as a message. This page checks event.source first, so it only trusts that one frame.
Press Module script to switch to <script type="module">. In a module, top-level names stay inside the module. Even var fruit no longer makes window.fruit.
<div id="banner">Named access demo</div><script>var fruit = "mango";let veggie = "carrot";function greet() { return "hi"; }parent.postMessage({ source: "global-explorer", mode: "classic", rows: [ ["'fruit' in window", String("fruit" in window)], ["window.veggie", String(window.veggie)], ["typeof window.greet", typeof window.greet], ["globalThis === window", String(globalThis === window)], ["window.window === window", String(window.window === window)], ["self === window", String(self === window)], ["window.banner exists", String(Boolean(window.banner))] ]}, "*");</script>Waiting for the frame to report.
Waiting for the frame to report…
Browsers also put some elements that have an id on window. So <div id="banner"> may show up as window.banner. This is called named access. Browsers keep it only so that very old sites still work. In real code, use document.querySelector("#banner") or document.getElementById("banner").
console.log(typeof window);
console.log(globalThis === window);Line 1 prints object, because a page has a window object. Line 2 prints true. globalThis is a name for the global object that works in every host. In a page, it gives you window.
var name = "Asha";
console.log(name);
console.log(window.name);Line 2 prints Asha. Line 3 prints Asha too. The browser already has a property called window.name. In a classic script, top-level var name doesn't make a new variable. It reuses that browser property. The browser turns anything you store in window.name into a string, so var name = 42 gives you "42".
So name is a poor global name. Use a local variable, or a clearer name such as profileName.
When code really needs "the global object, wherever I am running", use globalThis. It means:
- In a page script:
window, soglobalThis === windowistrue. (Strictly, the browser gives you a stand-in object called a WindowProxy. It passes everything on to the current window.) - In a worker: the worker's own global object, which is also called
self. - In Node.js: the Node.js global object, which is also called
global.
DOM and BOM: the page and the browser around it
SORT ITwindow as a houseThink of a house. The furniture inside is what you move around most. The house also has a number on the door. You remember which rooms you walked through. And the owner carries an ID card.
- In real life: The whole house
- In JavaScript:
window, the global object in a browser - In real life: The furniture you move around
- In JavaScript:
document, the page you can read and change - In real life: The house number on the door
- In JavaScript:
location, the current web address - In real life: The rooms you walked through
- In JavaScript:
history, the pages you visited in this tab - In real life: The owner’s ID card
- In JavaScript:
navigator, facts about the browser and device
The most important name on window for the next lesson is document. It is a live copy of the HTML page, made of objects. You can search it, read parts of it, and change it. The other names describe the browser around the page: the web address, the pages visited in this tab, the screen, and the device.
The DOM (Document Object Model) is the standard way to show a page as a tree of objects, called nodes. Scripts can read and change those nodes. The next lesson, "The DOM tree", looks at that tree up close.
BOM is short for Browser Object Model. It is a nickname, not an official standard. People use it for the browser objects that are not the page itself:
location: the web address of the page.history: the pages visited in this tab.navigator: facts about the browser and the device.screen: the size of the screen.- Pop-up dialogs, such as
alert.
Most of these are written down in the HTML Standard. There is no single official "BOM standard".
window. document is the page (the DOM); location, history, and navigator describe the browser around it (the BOM).console.log(typeof window.innerWidth);
console.log(window.innerWidth > 0);The viewport is the part of the browser window that shows the page. innerWidth is its width in pixels. Line 1 prints number. Line 2 prints true, because a visible viewport is always wider than 0.
Real sites usually change their look with CSS media queries (CSS rules that apply only at some screen sizes). They use JavaScript for behavior, such as opening a menu on small screens.
console.log(typeof location.href);
console.log(typeof location.pathname);
console.log(new URL(location.href).searchParams.get("q") ?? "no query");location.href is the whole web address. location.pathname is the part after the site name, such as /javascript/browser-environment. Lines 1 and 2 print string, because both are text.
Line 3 reads the query: the part of the address after ?. new URL(location.href) turns the address into an object with handy parts. Its searchParams.get("q") finds the value of q. For ?q=shoes, line 3 prints shoes. With no q, get gives null, and ?? swaps in no query. A search page can use the value to ask for matching results.
const greeting = navigator.language.startsWith("en")
? "Hello"
: "Welcome";
console.log(greeting);navigator.language is the reader's language as a short tag, such as en-GB for British English. Line 1 checks whether the tag starts with en. If it does, the greeting is Hello. If not, it is Welcome. Line 4 prints the greeting.
This is a small safe default, not a full translation system.
document.title = "Cart";
console.log(document.title);document.title is the text shown on the browser tab. Line 1 sets it to Cart, and line 2 prints Cart. A shop can change the title after the user adds an item. Keep the title short and clear.
Array.prototype.mapJSON.parsePromisedocument.querySelectorlocation.hrefhistory.backalertsetTimeoutconsole.logfetchprocess.envrequire
Sort each name by who provides it: the JavaScript language (ECMAScript), the DOM standard, the HTML standard, or another host. Careful: a name you use every day is not always part of the language.
const snapshot = { pathname: location.pathname, language: navigator.language, online: navigator.onLine, viewport: innerWidth + " × " + innerHeight, screenWidth: screen.width, devicePixelRatio, historyLength: history.length, title: document.title, readyState: document.readyState};These values are read only after the page appears in your browser. So the server never has to guess your screen size, language, or history. Resize the window and the width and height row changes.
The standards behind browser names
MAPBrowser tools look like one big pile of objects. In fact they come from several written standards. A standard is a rule book that every browser follows. Each standard covers a different part. This explains three puzzles:
Array.prototype.mapworks in Node.js, because it is part of the language.document.querySelectordoesn't work in Node.js, because it comes from a browser standard.fetchworks in more than one host, but it is still not part of the language.
So ask where a name comes from, not whether it "is JavaScript". The replay below runs three checks in a Node.js-like place, with no page:
Array.isArray([])is language code, so it works and givestrue.typeof documentgives"undefined", because there is no page.typeof globalThisgives"object", because every host has a global object.
Replay three small checks: language tools work in every host, but page tools don't.
script
languageValue: Array.isArray([]), pageApi: typeof document, sharedGlobal: typeof globalThis};console.log(result.languageValue);console.log(result.pageApi);console.log(result.sharedGlobal);Builders follow building codes. A building code is a shared set of rules. Because every team follows the same rules, houses built by different teams fit the same pipes, plugs, and doors.
- In real life: Rules for concrete and wiring
- In JavaScript: ECMAScript, the rules of the language
- In real life: Rules for rooms, doors, and house numbers
- In JavaScript: The HTML and DOM standards, for pages and moving between them
- In real life: Rules for pipes and power
- In JavaScript: Fetch, Console, CSSOM, and other standards
- In real life: Inspectors who check each building
- In JavaScript: Shared tests that check every browser follows the rules
Each row below names some tools and the standard that describes them. Read across to see why it matters to you. A "Living Standard" is one that is updated all the time, not in big numbered versions.
| What you use | Which standard describes it | Why it matters |
|---|---|---|
let, functions, arrays, promises | ECMAScript | They work in every host, because they are the language itself. |
document, elements, nodes, events | DOM Living Standard | This is how scripts see the page as a tree. |
window, location, history, timers, loading classic scripts | HTML Living Standard | This covers most of the browser around the page. |
fetch | Fetch Standard | Network requests are a web tool, not a keyword of the language. |
console.log | Console Standard, plus the host | The host gives you logging for developers. |
| CSS rules that scripts can read | CSSOM | Scripts can read and change some style information. |
console.log(window.setTimeout === setTimeout);
console.log(typeof setTimeout);Line 1 prints true. The short name setTimeout and window.setTimeout are the same browser function. Line 2 prints function.
setTimeout asks the browser to run some code later. It does not pause the code that is running now.
You don't need to remember standard names to write a click handler. But keep one habit. When a name is missing, ask: is it part of the language, a browser tool, a worker tool, or a Node.js tool? That one question saves a lot of confusion.
Where scripts run
REAL WORKER"JavaScript runs in the browser" is true, but it is not the whole story. There are four common places to run it:
- A classic page script runs in the page. It has
windowanddocument. - A module page script (
<script type="module">) also runs in the page and can use browser tools. But its top-level names stay inside the module. - A Web Worker runs JavaScript in the background, away from the page's main thread. The main thread is the single line of work that also handles clicks and draws the page. A worker has
self, but nodocument. - Node.js runs outside the browser. It has
processandglobal, but nowindow.
window, self, or global. Only the page script has document, so only it can change the page.A worker is useful for long calculations, because the page keeps reacting to clicks while the worker is busy. A worker can't change the page directly. It sends messages to the page instead.
Node.js is a different host again. Its process object helps with servers and scripts. But a Node.js program has no page.
console.log(typeof window === "object"
? "browser-like"
: "node-like");The ? : picks one of two texts. In a browser page, typeof window is "object", so it prints browser-like. In a normal Node.js program it prints node-like.
This check can help in code that both hosts share. But it is safer to check for the exact tool you need, such as typeof document. Don't guess the whole host from one name.
self.postMessage({ windowType: typeof window, documentType: typeof document, selfType: typeof self, importScriptsType: typeof importScripts, globalThisType: typeof globalThis});…………undefinedundefinedobjectfunctionobjectundefinedundefinedobjectobjectobjectStarting a real worker from the code on the left. If the browser blocks it, the worker column shows the expected values.
Each row below is one place where JavaScript runs. Read across to see its global names, whether it can change the page, and what it is usually used for.
| Where the code runs | Global names it has | Can it change the page? | What it is usually for |
|---|---|---|---|
| Classic page script | window, self, globalThis | Yes, through document. | Small page behavior, or older scripts. |
| Module page script | window, self, globalThis | Yes, through document. | Modern browser code split into files with import and export. |
| Web Worker | self, globalThis | No. It has no document. | Long calculations or background work that must not freeze the page. |
| Node.js | global, globalThis, process | No. There is no browser page. | Servers, scripts, build tools, and tests. |
Where you will use this
You use these ideas whenever code reaches outside the language. The code below is normal front-end code. It does four things:
- Line 1 finds an element on the page, using the DOM.
- Line 4 reads the web address from
location. - Line 5 asks
navigatorwhether the browser thinks it is online. - Lines 9 and 10 listen for two browser events: the browser going online, and going offline.
const status = document.querySelector("#status"); function describePage() { const path = location.pathname; const online = navigator.onLine ? "online" : "offline"; status.textContent = `You are on ${path} and currently ${online}.`;} window.addEventListener("online", describePage);window.addEventListener("offline", describePage);describePage();history.pushState({}, "", "#search");
console.log(location.hash);history.pushState changes the address and adds a step to the tab's history. It does not load a new page. The #search part of an address is called the hash, so line 2 prints #search.
This example has no Run button. The lesson editor runs code in a locked-down frame that has no real web address of its own, so pushState can't work there. Try it on a normal page of your own site.
This is why it helps to keep the language and the host apart. Three examples from the status code above:
- If the code fails in a Node.js test, suspect
documentfirst. Node.js has no page. - If
statusisnull, the element is not on the page, or the script ran before the element existed. - If
navigator.onLinesays online but requests still fail, remember that it is only the browser's guess. It doesn't prove that your server can be reached.
Server rendering means a server makes the page's HTML first, before any browser is involved. So browser-only values such as innerWidth, navigator.language, and history.length don't exist yet.
Read them only after the component appears in the browser (after it mounts). Or start with a fixed value from the server and update it later. Otherwise the server's HTML and the browser's HTML won't match. That problem is called a hydration mismatch.
Common misconceptions
DEBUG- "Every global name is on
window." In a classic script, top-levellet,const, andclassmake global names that are not properties onwindow. - "Modules can't use browser tools." A browser module can use
document,location, and the rest. Only its own top-level names stay inside the module. - "BOM is an official standard, like the DOM." BOM is only a nickname. Most of these objects are described in the HTML Standard and other web standards.
- "
fetchandsetTimeoutare part of the language." They come from the host. The language describes promises. The host adds tools such as timers and network requests, which make and use promises. - "A worker is a small page." A worker runs JavaScript, but it has no
document. It can't change the page directly. - "Named access is handy, so I should use it." It is old behavior, and names can clash. Find elements through
documentinstead.
alert("Saved");
const confirmed = confirm("Delete this item?");
const answer = prompt("Your name?");
console.log(confirmed, answer);alert, confirm, and prompt each show a pop-up box. The page stops reacting until the reader answers. This code has no Run button, because an automatic editor can't answer the pop-ups.
Modern sites usually use a <dialog> element or their own form instead. These don't freeze the page's code while they wait.
Practice exercises
6 EXERCISESThis code is a classic script. What do the two console.log lines print?
var pet = "otter";
let snack = "kelp";
console.log("pet" in globalThis);
console.log(globalThis.snack);Line 3 prints true, because top-level var pet puts pet on globalThis. Line 4 prints undefined, because top-level let snack is not a property on globalThis.
Who provides document.querySelector: ECMAScript, the DOM, HTML/BOM, another host tool, or Node.js?
The DOM provides document.querySelector. It searches the page's tree for the first element that matches.
This function works in one browser tab, but breaks after the HTML changes. Rewrite it so it doesn't rely on named access.
function updateBanner() {
banner.textContent = "Ready";
}function updateBanner() {
const banner = document.querySelector("#banner");
if (banner) banner.textContent = "Ready";
}Don't rely on old named access through window.banner. Find the element with document.querySelector. Then check that it exists before you change it.
This object copies what a real worker reports. Type the three words it prints, separated by commas.
const workerGlobal = {
windowType: "undefined",
documentType: "undefined",
selfType: "object"
};
console.log(workerGlobal.windowType + "," + workerGlobal.documentType + "," + workerGlobal.selfType);The program prints undefined,undefined,object. A worker has no window and no document, but self is its global object.
Which object do you use to read the page title: window, document, navigator, or history?
document stands for the page, so document.title reads the page's title.
Does navigator.onLine prove that your server can be reached? Answer in one short sentence.
No. navigator.onLine is a useful guess for showing online or offline in the page. Only a real request to your server shows that the server answers.
Check your understanding
7 QUESTIONSQuestion 1 of 7What is the browser environment?
Choose an answer to see the explanation.
Question 2 of 7What does this classic script print?
Read the code, then predictvar fruit = "mango"; let veggie = "carrot"; console.log("fruit" in globalThis); console.log(globalThis.veggie);Choose an answer to see the explanation.
Question 3 of 7Which of these is part of the language (ECMAScript), not a browser tool?
Choose an answer to see the explanation.
Question 4 of 7What does
globalThisgive you in a web page script?Choose an answer to see the explanation.
Question 5 of 7Which sentence about module scripts is correct?
Choose an answer to see the explanation.
Question 6 of 7What does the nickname BOM usually mean?
Choose an answer to see the explanation.
Question 7 of 7What does this print in Node.js, for example in a test?
Read the code, then predictconsole.log(typeof window); console.log(typeof globalThis);Choose an answer to see the explanation.
Key takeaways
- ECMAScript is the JavaScript language itself. The browser, as the host, adds web tools around it.
- In a page script,
windowis the global object, andglobalThis === windowistrue. - In a classic script, top-level
varand function declarations become properties onwindow. Top-levellet,const, andclassdon't, and nothing at the top level of a module does. - The DOM is the standard for the page as a tree of objects. BOM is a nickname for the browser objects around the page, and most of them are described in the HTML Standard.
- Workers and Node.js run the same language, but they don't have the same global names as a page.
Final definition: the browser environment is JavaScript plus the objects a browser adds, based on shared standards, so your code can read and change a web page.
Up next: The DOM tree.