Mert Özen Further With Every Line
Frontend JavaScript Basics — #17

The JavaScript BOM: window, location, navigator and Timers

Mert Özen Nov 3, 2026 7 min 7 views
The JavaScript BOM: window, location, navigator and Timers

We get to know the browser objects: the global window, location for the address, navigating with history, navigator and screen info, timers with setTimeout and setInterval, and why alert, confirm and prompt are rarely used.

Version note: The code in this post targets ES2026 and current browsers (Chrome, Edge, Firefox, Safari).

Predict First

Three lines of code. The middle one sets up a timer and passes zero as the delay:

console.log("1");
setTimeout(() => console.log("2"), 0);
console.log("3");

What do you see in the console, and in what order? Doesn't zero milliseconds mean "right now"? Make a guess before you keep reading. We'll give the answer in the section on timers.

DOM and BOM: The Stage and the Theater

Picture a theater. The set, the actors and the lights on stage are the play itself; that's exactly what the DOM is, the content of the page. But there's also the building: the doors, the corridors, the curtain, the clock, the seats where the audience sits. The play may change, but the building stays the same. In the browser, that building is the BOM, the Browser Object Model.

BOM is the collective name for the objects that let you talk to the parts of the browser outside the page: the window itself, the address bar, the back and forward buttons, the browser's language, the size of the screen. It isn't actually the name of an official standard; most of these objects are defined in the HTML standard today and work the same way in all current browsers. Still, the name is very handy for talking about them together.

window: The Roof Over Everything

At the top of every script running in the browser sits the window object. The document and console we've been using all along are actually its properties. Paste this into the console and try it:

console.log(window.document === document); // true
window.console.log("This works too");

var oldWay = "with var";
let newWay = "with let";
console.log(window.oldWay); // "with var"
console.log(window.newWay); // undefined

window is the global object. When you write document, the engine first looks for it among your variables and, if it can't find it there, checks window. That's why we usually don't write the window. prefix.

The last two lines show a difference we touched on earlier when we talked about why we no longer use var. A variable declared with var at the top level becomes a property of window and can clash with the browser's own names. let and const are not added to window. One more small note: globalThis, which arrived with ES2020, gives you the global object no matter which environment you run in; in the browser, globalThis === window.

location and history: Address and History

location

location lets you read the URL in the address bar piece by piece and change it. Imagine the address is https://example.com/products?category=books&page=2#reviews:

location.href;     // "https://example.com/products?category=books&page=2#reviews"
location.protocol; // "https:"
location.hostname; // "example.com"
location.pathname; // "/products"
location.search;   // "?category=books&page=2"
location.hash;     // "#reviews"

Type these lines into the console on any site and break that page's address into its parts. search gives you the query part after the question mark as a raw string. We'll cover URLSearchParams, which makes pulling out the value of category easy, in the Intermediate series.

location isn't only for reading:

location.href = "https://developer.mozilla.org"; // goes to that address
location.reload();                               // reloads the page
location.replace("https://developer.mozilla.org"); // goes there but leaves no history entry

Assigning a new address to href is like the user clicking a link: the browser goes there, and the back button returns to the old page. replace takes the place of the current page; the back button skips it. That's usually what you want when redirecting the user to the home page after a login page.

history

history represents the browser's history in that tab. You can do the job of the back and forward buttons with your own buttons:

history.back();    // one page back
history.forward(); // one page forward
history.go(-2);    // two pages back
history.length;    // how many entries this tab's history has

For security reasons you can't read the addresses in the history; you only know how many entries there are and move between them. pushState, which changes the address bar without reloading the page, is another one for the Intermediate series.

Save and open this file, then resize the window:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Browser Info</title>
</head>
<body>
  <p id="language"></p>
  <p id="connection"></p>
  <p id="size"></p>
  <button id="back">Go back</button>
  <script>
    const language = document.getElementById("language");
    const connection = document.getElementById("connection");
    const size = document.getElementById("size");

    language.textContent = `Browser language: ${navigator.language}`;

    function showConnection() {
      connection.textContent = navigator.onLine ? "You're on a network." : "You seem to be offline.";
    }

    function showSize() {
      size.textContent = `Window: ${window.innerWidth} x ${window.innerHeight}, screen: ${screen.width} x ${screen.height}`;
    }

    showConnection();
    showSize();

    window.addEventListener("online", showConnection);
    window.addEventListener("offline", showConnection);
    window.addEventListener("resize", showSize);

    document.getElementById("back").addEventListener("click", () => history.back());
  </script>
</body>
</html>

navigator.language gives you the user's browser language, for example "en-US". You'll find all their languages, in order of preference, in the navigator.languages array. It's a good starting point for opening your page in the user's language.

navigator.onLine tells you whether the device is connected to a network, and you hear about changes through the online and offline events on window. To try it, switch the connection to Offline in the DevTools Network tab. One caveat, though: true doesn't mean you can reach the internet, only that you're connected to some network. Use it to give the user a hint like "your connection may be down," not to switch features off.

navigator.clipboard lets you write to and read from the clipboard: navigator.clipboard.writeText("Hello"). It requires a secure context such as HTTPS and usually works after a user action like a click. Since it returns its result as a promise, we'll see the details after we learn asynchronous programming in the Intermediate series. Also avoid guessing "which browser is this?" from navigator.userAgent. Ask directly whether a feature exists: if ("clipboard" in navigator).

screen.width and screen.height give you the whole monitor, while window.innerWidth and innerHeight give you the visible area of the page. The second pair is what changes as you shrink the window. Even so, the real place to adapt a page's layout to the screen is CSS media queries; use these values when you genuinely need to do a calculation in JavaScript.

Timers: setTimeout and setInterval

setTimeout runs a function once after a given delay. setInterval runs it again and again at a given interval. Both return an id; you cancel the timer by passing that id to clearTimeout or clearInterval. Let's build a countdown:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Countdown</title>
</head>
<body>
  <p id="counter">10</p>
  <button id="start">Start</button>
  <button id="stop">Stop</button>
  <p id="message"></p>
  <script>
    const counterArea = document.getElementById("counter");
    const message = document.getElementById("message");
    let remaining = 10;
    let intervalId = null;

    document.getElementById("start").addEventListener("click", () => {
      if (intervalId !== null) return; // already running
      if (remaining === 0) remaining = 10;

      intervalId = setInterval(() => {
        remaining = remaining - 1;
        counterArea.textContent = remaining;

        if (remaining === 0) {
          clearInterval(intervalId);
          intervalId = null;
          message.textContent = "Time's up!";
          setTimeout(() => {
            message.textContent = "";
          }, 3000);
        }
      }, 1000);
    });

    document.getElementById("stop").addEventListener("click", () => {
      clearInterval(intervalId);
      intervalId = null;
    });
  </script>
</body>
</html>

Press Start and the number goes down by one every second. When it hits zero, we stop the repetition with clearInterval, write "Time's up!" and clear the message three seconds later with setTimeout. The reason we check intervalId: if Start is pressed twice, two separate intervals run and the counter ticks twice as fast.

Now the answer to the opening question: you see 1, 3, 2, in that order. setTimeout doesn't run the function right away; it makes a note to "run this after at least this much time." Even with zero milliseconds, the timer's function only gets its turn after the currently running code has completely finished. That's why 3 is printed first. The mechanism behind this is called the event loop, and we'll go through it step by step in the Intermediate series. For now, keep this in mind: the delay you pass isn't a guarantee, it's a minimum. On top of that, browsers slow down timers in background tabs to save battery and performance.

alert, confirm and prompt

The browser has three ready-made dialog boxes:

alert("Saved.");                                        // just shows a message
const confirmed = confirm("Do you want to delete it?"); // true or false
const userName = prompt("What's your name?", "Guest");  // the typed string, or null on Cancel

console.log(confirmed, userName);

They're very easy to use, but real projects rarely choose them. While a dialog is open, the whole page freezes: the user can't click anything else, and your code waits on that line too. You can't change how they look, they read like a message from the browser rather than from your site, and users trust boxes like these less and less. Some browsers even offer the user a way to block dialogs that keep popping up. Showing your own message area inside the page, or using HTML's <dialog> element, gives a much better experience. And when debugging, use console.log instead of alert.

Common Pitfalls

Calling the function instead of passing it

If you write setTimeout(greet(), 2000), greet runs immediately and nothing happens two seconds later. The rule from the events post is the same here: setTimeout(greet, 2000).

Forgetting to stop an interval

A setInterval keeps running until you call clearInterval or the page closes. Even when the user moves to another screen, it can keep working in the background. Wherever you set up an interval, think from the start about where you'll stop it.

Passing a string to a timer

setTimeout("console.log('hi')", 1000) also works; the browser interprets the string as code. That's both slow and a security risk. Always pass a function.

Trusting navigator.onLine too much

Seeing true doesn't guarantee your requests will reach the server. The only way to know whether the connection really works is to make a request and look at the result.

A Small Experiment

★☆☆ In the console, use a setTimeout to change the page title (document.title) to "Still there?" after five seconds.

★★☆ Predict the output before running, then try it in the console:

setTimeout(() => console.log("A"), 100);
setTimeout(() => console.log("B"), 0);
console.log("C");

★★★ Show a live clock on the screen: update the hours, minutes and seconds every second with setInterval. Put a "Stop / Resume" button next to it. Also show the window's width in the tab title and update it whenever the window is resized.

Writing the clock to the screen in that last exercise means dealing with dates and times. That's exactly what we'll talk about in the next post: creating dates in JavaScript, calculating the difference between two dates and showing dates in a readable format.