completefrontend
Open lab My progress
THE JAVASCRIPT FIELD GUIDE

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.

By the end you can explain
  • 01
    What the browser addsTell the JavaScript language (ECMAScript) apart from the tools the browser adds, such as window, document, location, timers, and fetch.
  • 02
    Which names go on windowPredict which top-level names become properties on window, and why modules work differently.
  • 03
    Where 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 document exist?
  • 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 main idea

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.

Plain math works in any hostPop out in the code editor (opens in a new tab)JavaScript
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.

Real-life analogyThe engine and the car

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, and screen
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

INTERACTIVE

In 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 var and top-level function declarations become properties on window. You saw this in the var and the global object lesson.
  • Top-level let, const, and class make global names too, but they are not properties on window. 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.

Left: var fruit = "mango" puts a fruit card into the window cart, so window.fruit is "mango". Right: let fruit = "mango" puts the value in its own box called fruit, outside window, so window.fruit is undefined.var fruit = "mango"fruit: "mango"windowwindow.fruit is "mango"let fruit = "mango""mango"fruitnot on windowwindow.fruit is undefined
In a classic script, top-level var puts the name on window. Top-level let makes a global name too, but keeps it off window.
Step through a top-level var or let
Step 0 of 5Ready
Your turn: follow the blue line

Step through one classic script. Watch the difference between a global name and a property on the global object.

Running in
  1. script
Next: line 1
function greet() {  return "hello from a classic script";}console.log("fruit" in globalThis);console.log(globalThis.fruit);console.log(typeof greet);
CallStoreChangeResultBlue line: runs next. Ran: already executed.
Recent returnsNothing yet. Start with the blue line.
Change line 1, then predict lines 5 and 6

Changing line 1 starts the replay again. The code shown is the code being explained.

A guided replay recorded from real JavaScript calls, not an engine debugger. Step follows executed statements; Back reviews a snapshot. Reset starts a fresh run.

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.

What lands on window?
Classic script inside the framePop out in the code editor (opens in a new tab)HTML
<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>
What the frame reportsclassic

Waiting for the frame to report.

Try it yourself

Waiting for the frame to report…

The frame is a small page with locked-down permissions (sandbox='allow-scripts'). It only runs the fixed code shown here, and this page only accepts messages from that one frame. The last row shows named access because it exists, not because you should use it.
Named access is old behavior

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").

window and globalThis in a pagePop out in the code editor (opens in a new tab)JavaScript
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.

A top-level var can clash with a browser namePop out in the code editor (opens in a new tab)JavaScript
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, so globalThis === window is true. (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 IT
Real-life analogywindow as a house

Think 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".

A window labelled window. On the left, a document card, labelled DOM: the page. On the right, location, history, and navigator cards, labelled BOM: the browser.windowdocumentDOM:the pagelocationhistorynavigatorBOM: the browser
All of these live on window. document is the page (the DOM); location, history, and navigator describe the browser around it (the BOM).
Read the width of the page areaPop out in the code editor (opens in a new tab)JavaScript
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.

Read parts of the web addressPop out in the code editor (opens in a new tab)JavaScript
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.

Pick a greeting from the reader's languagePop out in the code editor (opens in a new tab)JavaScript
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.

Change the text on the browser tabPop out in the code editor (opens in a new tab)JavaScript
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.

Who provides this?
  • Array.prototype.map
  • JSON.parse
  • Promise
  • document.querySelector
  • location.href
  • history.back
  • alert
  • setTimeout
  • console.log
  • fetch
  • process.env
  • require
Try it yourself
0 of 12 correct

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.

Choose a category for every card. You can change an answer at any time; Reset clears them all.
Live readings from your browser
Read values from the browserPop out in the code editor (opens in a new tab)JavaScript
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};
Your browser sayslive
Try it yourself

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.

This only reads values. Nothing is sent anywhere. The values depend on your browser, your device, and how you reached this page.

The standards behind browser names

MAP

Browser 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.map works in Node.js, because it is part of the language.
  • document.querySelector doesn't work in Node.js, because it comes from a browser standard.
  • fetch works 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 gives true.
  • typeof document gives "undefined", because there is no page.
  • typeof globalThis gives "object", because every host has a global object.
Step through three host checks
Step 0 of 4Ready
Your turn: follow the blue line

Replay three small checks: language tools work in every host, but page tools don't.

Running in
  1. script
Next: line 1
  languageValue: Array.isArray([]),  pageApi: typeof document,  sharedGlobal: typeof globalThis};console.log(result.languageValue);console.log(result.pageApi);console.log(result.sharedGlobal);
CallStoreChangeResultBlue line: runs next. Ran: already executed.
Recent returnsNothing yet. Start with the blue line.
A guided replay recorded from real JavaScript calls, not an engine debugger. Step follows executed statements; Back reviews a snapshot. Reset starts a fresh run.
Real-life analogySpecs are building codes

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.

Which standard describes which tools
What you useWhich standard describes itWhy it matters
let, functions, arrays, promisesECMAScriptThey work in every host, because they are the language itself.
document, elements, nodes, eventsDOM Living StandardThis is how scripts see the page as a tree.
window, location, history, timers, loading classic scriptsHTML Living StandardThis covers most of the browser around the page.
fetchFetch StandardNetwork requests are a web tool, not a keyword of the language.
console.logConsole Standard, plus the hostThe host gives you logging for developers.
CSS rules that scripts can readCSSOMScripts can read and change some style information.
setTimeout comes from the browserPop out in the code editor (opens in a new tab)JavaScript
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 window and document.
  • 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 no document.
  • Node.js runs outside the browser. It has process and global, but no window.
Three windows. A page script has the global object window and has document. A worker has self and no document. Node.js has global and no document.page scriptwindowhas documentin the pageworkerselfno documentin the backgroundNode.jsglobalno documentoutside the browser
Each place has its own global object: 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.

Check whether there is a windowPop out in the code editor (opens in a new tab)JavaScript
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.

Where scripts run
Code that runs inside the workerPop out in the code editor (opens in a new tab)JavaScript
self.postMessage({  windowType: typeof window,  documentType: typeof document,  selfType: typeof self,  importScriptsType: typeof importScripts,  globalThisType: typeof globalThis});
Global names in each placepage · worker · Node.js
Page script
typeof window…
typeof document…
typeof self…
typeof globalThis…
Worker
typeof windowundefined
typeof documentundefined
typeof selfobject
typeof importScriptsfunction
typeof globalThisobject
Node.js
typeof windowundefined
typeof documentundefined
typeof processobject
typeof globalobject
typeof globalThisobject
Try it yourself

Starting a real worker from the code on the left. If the browser blocks it, the worker column shows the expected values.

The page column is read from this page after it appears. The worker column comes from a real worker when the browser allows it. The Node.js column is fixed, because this tab is not running Node.js.

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.

Four places where JavaScript runs that are easy to mix up
Where the code runsGlobal names it hasCan it change the page?What it is usually for
Classic page scriptwindow, self, globalThisYes, through document.Small page behavior, or older scripts.
Module page scriptwindow, self, globalThisYes, through document.Modern browser code split into files with import and export.
Web Workerself, globalThisNo. It has no document.Long calculations or background work that must not freeze the page.
Node.jsglobal, globalThis, processNo. 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 navigator whether the browser thinks it is online.
  • Lines 9 and 10 listen for two browser events: the browser going online, and going offline.
A status line that knows the page and the networkPop out in the code editor (opens in a new tab)JavaScript
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();
Change the web address without loading a new pageJavaScript
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 document first. Node.js has no page.
  • If status is null, the element is not on the page, or the script ran before the element existed.
  • If navigator.onLine says online but requests still fail, remember that it is only the browser's guess. It doesn't prove that your server can be reached.
When the page is first made on a server

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-level let, const, and class make global names that are not properties on window.
  • "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.
  • "fetch and setTimeout are 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 document instead.
Pop-up dialogs stop the pageJavaScript
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 EXERCISES
Exercise 1 · Warm-upPredict the two global checks

This code is a classic script. What do the two console.log lines print?

Starter codePop out in the code editor (opens in a new tab)JavaScript
var pet = "otter";
let snack = "kelp";
console.log("pet" in globalThis);
console.log(globalThis.snack);

Answer, then press Check. Spacing and letter case don’t matter.

    Exercise 2 · PracticeName who provides it

    Who provides document.querySelector: ECMAScript, the DOM, HTML/BOM, another host tool, or Node.js?

    Answer, then press Check. Spacing and letter case don’t matter.

      Exercise 3 · PracticeFind the bug

      This function works in one browser tab, but breaks after the HTML changes. Rewrite it so it doesn't rely on named access.

      Starter codePop out in the code editor (opens in a new tab)JavaScript
      function updateBanner() {
        banner.textContent = "Ready";
      }
        Exercise 4 · ChallengeCompare a worker's global names

        This object copies what a real worker reports. Type the three words it prints, separated by commas.

        Starter codePop out in the code editor (opens in a new tab)JavaScript
        const workerGlobal = {
          windowType: "undefined",
          documentType: "undefined",
          selfType: "object"
        };
        console.log(workerGlobal.windowType + "," + workerGlobal.documentType + "," + workerGlobal.selfType);

        Answer, then press Check. Spacing and letter case don’t matter.

          Exercise 5 · PracticeFind the page object

          Which object do you use to read the page title: window, document, navigator, or history?

          Answer, then press Check. Spacing and letter case don’t matter.

            Exercise 6 · ChallengeDon't trust a browser guess too much

            Does navigator.onLine prove that your server can be reached? Answer in one short sentence.

            Answer, then press Check. Spacing and letter case don’t matter.

              Check your understanding

              7 QUESTIONS
              The browser environment quiz · 7 questionsScore: first tries count
              1. Question 1 of 7What is the browser environment?

                Choose an answer to see the explanation.

              2. Question 2 of 7What does this classic script print?

                Read the code, then predictPop out in the code editor (opens in a new tab)JavaScript
                var fruit = "mango";
                let veggie = "carrot";
                console.log("fruit" in globalThis);
                console.log(globalThis.veggie);

                Choose an answer to see the explanation.

              3. Question 3 of 7Which of these is part of the language (ECMAScript), not a browser tool?

                Choose an answer to see the explanation.

              4. Question 4 of 7What does globalThis give you in a web page script?

                Choose an answer to see the explanation.

              5. Question 5 of 7Which sentence about module scripts is correct?

                Choose an answer to see the explanation.

              6. Question 6 of 7What does the nickname BOM usually mean?

                Choose an answer to see the explanation.

              7. Question 7 of 7What does this print in Node.js, for example in a test?

                Read the code, then predictPop out in the code editor (opens in a new tab)JavaScript
                console.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, window is the global object, and globalThis === window is true.
              • In a classic script, top-level var and function declarations become properties on window. Top-level let, const, and class don'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.

              CompleteFrontend Clear concepts. Working examples.