Skip to main content

The Global Object in JavaScript

Every JavaScript environment provides a special object that sits at the top of the scope chain and holds built-in functions, global variables, and environment-specific APIs. In browsers, it is window. In Node.js, it is global. In web workers, it is self. For years, writing cross-environment JavaScript meant guessing which name to use. Then globalThis arrived and unified everything.

This guide explains what the global object is, how it differs across environments, how variable declarations interact with it, what built-in properties it provides, and most importantly, how to use it responsibly without polluting the global namespace.

globalThis: The Universal Global Object

Before ES2020, accessing the global object in a cross-environment way was surprisingly awkward. You had to write something like this:

// The old, ugly way to get the global object
var globalObj =
typeof window !== "undefined" ? window :
typeof global !== "undefined" ? global :
typeof self !== "undefined" ? self :
this;

globalThis was introduced in ES2020 to solve this problem. It is a standardized reference to the global object that works in every JavaScript environment:

console.log(globalThis);
// In a browser: Window { ... }
// In Node.js: Object [global] { ... }
// In a worker: DedicatedWorkerGlobalScope { ... }

Using globalThis

globalThis always points to the global object, no matter where your code runs:

// Works everywhere
globalThis.myValue = 42;
console.log(globalThis.myValue); // 42

// Accessing built-in globals
console.log(globalThis.parseInt("10")); // 10
console.log(globalThis.isNaN(NaN)); // true
console.log(globalThis.Math.PI); // 3.141592653589793
console.log(globalThis.JSON.stringify({})); // "{}"

When to Use globalThis

In practice, you rarely need to reference globalThis directly. Most global functions like parseInt, setTimeout, and JSON are available without qualifying them:

// You don't need to write this:
globalThis.console.log("Hello");
globalThis.setTimeout(() => {}, 1000);

// Just write:
console.log("Hello");
setTimeout(() => {}, 1000);

globalThis is useful when you:

  • Write code that must run in multiple environments (browser, Node.js, Deno, workers)
  • Need to explicitly read or write a global property
  • Create polyfills that need to attach to the global scope
  • Check for the existence of environment-specific features
// Feature detection across environments
if (typeof globalThis.fetch === "function") {
console.log("Fetch API is available");
} else {
console.log("Fetch API is NOT available, need a polyfill");
}

// Adding a polyfill to the global scope
if (typeof globalThis.structuredClone === "undefined") {
globalThis.structuredClone = function(obj) {
return JSON.parse(JSON.stringify(obj));
};
}

window in Browsers, global in Node.js

Before globalThis, each JavaScript environment had its own name for the global object. Understanding these is important because you will encounter them in existing code.

window in Browsers

In browser environments, the global object is window. It represents the browser window or tab and contains everything from DOM APIs to timers to the JavaScript globals:

// In a browser console:
console.log(window === globalThis); // true

// window properties include:
console.log(window.innerWidth); // Browser window width
console.log(window.innerHeight); // Browser window height
console.log(window.location.href); // Current URL
console.log(window.document); // The DOM document
console.log(window.navigator.userAgent); // Browser info

window has a dual role in browsers:

  1. It is the global object (holds global variables and functions)
  2. It is the browser window object (has properties like innerWidth, location, history)
// These are all equivalent in a browser:
console.log(window.setTimeout === setTimeout); // true
console.log(window.console === console); // true
console.log(window.Array === Array); // true
console.log(window.Math === Math); // true
console.log(window.globalThis === globalThis); // true

global in Node.js

In Node.js, the global object is called global:

// In Node.js:
console.log(global === globalThis); // true

// Node.js-specific globals
console.log(global.process.version); // e.g., "v20.10.0"
console.log(global.Buffer); // Buffer class for binary data
console.log(global.setTimeout); // Also available in Node.js

self in Web Workers and Service Workers

Web workers and service workers do not have a window object (because they have no DOM access). Their global object is referenced via self:

// Inside a Web Worker:
console.log(self === globalThis); // true
self.postMessage("Hello from the worker!");

Cross-Environment Summary

EnvironmentGlobal Object NameglobalThis Works?
Browser (main thread)windowYes
Browser (web worker)selfYes
Browser (service worker)selfYes
Node.jsglobalYes (v12+)
DenoglobalThis (no window in scripts)Yes
tip

When writing code that should work in multiple environments, always use globalThis. When writing browser-only code, using window is perfectly fine and is actually more common in practice. When writing Node.js-only code, you can use global, but globalThis is equally valid.

Global Variables and var vs. let/const at the Top Level

How a variable becomes "global" depends on how you declare it. The behavior is different for var, let/const, and undeclared assignments.

var at the Top Level Creates Global Object Properties

When you use var outside of any function, the variable becomes a property of the global object:

var appName = "MyApp";

console.log(window.appName); // "MyApp" (in a browser)
console.log(globalThis.appName); // "MyApp" (anywhere)

This means var declarations at the top level are accessible through the global object, which can lead to unintended interactions with other scripts on the page.

let and const Do NOT Create Global Object Properties

This is a crucial difference. let and const at the top level create global variables, but they do not become properties of the global object:

let userName = "Alice";
const API_KEY = "abc123";

console.log(window.userName); // undefined
console.log(window.API_KEY); // undefined

// But they ARE accessible as global variables in the script scope
console.log(userName); // "Alice"
console.log(API_KEY); // "abc123"

The variables exist in a "script scope" that is separate from the global object. They are globally accessible within your JavaScript code, but they do not pollute the window object.

Undeclared Variables (Implicit Globals)

Assigning a value to a variable without declaring it (no var, let, or const) creates a property on the global object in non-strict mode:

// Non-strict mode
function oops() {
accidentalGlobal = "I'm a global!"; // No declaration keyword!
}

oops();
console.log(window.accidentalGlobal); // "I'm a global!"
console.log(accidentalGlobal); // "I'm a global!"

This is one of the most dangerous pitfalls in JavaScript. A simple typo can create an unintended global variable:

function calculateTotal(items) {
let total = 0;
for (let i = 0; i < items.length; i++) {
toal += items[i].price; // Typo! "toal" instead of "total"
// In non-strict mode, this silently creates window.toal
}
return total; // Returns 0 because "total" was never modified
}

In strict mode, assigning to an undeclared variable throws a ReferenceError:

"use strict";

function safe() {
accidentalGlobal = "oops"; // ReferenceError: accidentalGlobal is not defined
}
danger

Always use "use strict" or ES modules (which are strict by default) to prevent accidental global variable creation. Undeclared assignments are one of the most common sources of subtle bugs in JavaScript.

Explicit Global Object Assignment

When you intentionally want to create a global variable that is accessible across scripts or modules, assign it directly to the global object:

// Intentional global (clear and explicit)
globalThis.APP_CONFIG = {
apiUrl: "https://api.example.com",
debug: false,
version: "2.1.0"
};

// Accessible from anywhere
console.log(APP_CONFIG.apiUrl); // "https://api.example.com"

This is explicit and intentional, making it clear that the variable is meant to be global.

Complete Comparison

// 1. var (becomes a window property)
var varGlobal = "var";
console.log(window.varGlobal); // "var"
console.log(globalThis.varGlobal); // "var"

// 2. let (does NOT become a window property)
let letGlobal = "let";
console.log(window.letGlobal); // undefined
console.log(letGlobal); // "let" (accessible as a variable, just not on window)

// 3. const (does NOT become a window property)
const constGlobal = "const";
console.log(window.constGlobal); // undefined
console.log(constGlobal); // "const"

// 4. Undeclared (non-strict) (becomes a window property)
undeclaredGlobal = "oops";
console.log(window.undeclaredGlobal); // "oops"

// 5. Explicit assignment (becomes a window property)
globalThis.explicitGlobal = "explicit";
console.log(window.explicitGlobal); // "explicit"
DeclarationGlobal variable?Property of globalThis?
var x = 1 (top level)YesYes
let x = 1 (top level)YesNo
const x = 1 (top level)YesNo
x = 1 (undeclared, non-strict)YesYes
globalThis.x = 1YesYes

Global Functions and Properties

The global object comes preloaded with a set of built-in functions, constructors, and values. These are available in all JavaScript environments.

Global Value Properties

console.log(globalThis.undefined);  // undefined
console.log(globalThis.NaN); // NaN
console.log(globalThis.Infinity); // Infinity

You rarely access these through globalThis. They are typically used directly:

let x;
console.log(x === undefined); // true
console.log(isNaN(NaN)); // true
console.log(1 / 0 === Infinity); // true

Global Functions

These functions are available without importing or qualifying them:

// Parsing functions
console.log(parseInt("42px")); // 42
console.log(parseFloat("3.14abc")); // 3.14

// Encoding/Decoding URIs
console.log(encodeURIComponent("hello world & more"));
// "hello%20world%20%26%20more"
console.log(decodeURIComponent("hello%20world"));
// "hello world"

console.log(encodeURI("https://example.com/path with spaces"));
// "https://example.com/path%20with%20spaces"

// Type checking
console.log(isNaN("abc")); // true
console.log(isFinite(42)); // true
console.log(isFinite(Infinity)); // false

Global Constructors and Objects

The global object holds all built-in constructors:

// Primitive wrappers
console.log(globalThis.String); // ƒ String()
console.log(globalThis.Number); // ƒ Number()
console.log(globalThis.Boolean); // ƒ Boolean()
console.log(globalThis.Symbol); // ƒ Symbol()
console.log(globalThis.BigInt); // ƒ BigInt()

// Data structures
console.log(globalThis.Object); // ƒ Object()
console.log(globalThis.Array); // ƒ Array()
console.log(globalThis.Map); // ƒ Map()
console.log(globalThis.Set); // ƒ Set()
console.log(globalThis.WeakMap); // ƒ WeakMap()
console.log(globalThis.WeakSet); // ƒ WeakSet()

// Error types
console.log(globalThis.Error); // ƒ Error()
console.log(globalThis.TypeError); // ƒ TypeError()
console.log(globalThis.RangeError); // ƒ RangeError()

// Other built-ins
console.log(globalThis.Promise); // ƒ Promise()
console.log(globalThis.RegExp); // ƒ RegExp()
console.log(globalThis.Date); // ƒ Date()
console.log(globalThis.ArrayBuffer); // ƒ ArrayBuffer()

// Utility objects (not constructors)
console.log(globalThis.Math); // Math object
console.log(globalThis.JSON); // JSON object
console.log(globalThis.console); // Console object
console.log(globalThis.Intl); // Intl object

Browser-Specific Globals

In browsers, window provides additional properties that are not part of the JavaScript language but are part of the Web APIs:

// Timers
setTimeout(() => console.log("delayed"), 1000);
setInterval(() => console.log("repeated"), 2000);
requestAnimationFrame(() => console.log("before repaint"));

// Network
fetch("https://api.example.com/data");

// DOM
document.getElementById("app");
document.querySelector(".container");

// Navigation
console.log(location.href);
console.log(navigator.language);
console.log(history.length);

// Storage
localStorage.setItem("key", "value");
sessionStorage.getItem("key");

// Dialogs
alert("Hello!");
const answer = confirm("Are you sure?");
const input = prompt("Enter your name:");

// Screen info
console.log(screen.width);
console.log(screen.height);

Node.js-Specific Globals

Node.js provides its own set of globals:

// Process information
console.log(process.env.NODE_ENV);
console.log(process.argv);
console.log(process.cwd());
console.log(process.pid);

// Buffer for binary data
const buf = Buffer.from("Hello");

// Timers (also available, same as browser)
setTimeout(() => {}, 1000);
setInterval(() => {}, 1000);
setImmediate(() => {}); // Node.js-specific

// Module system (CommonJS, in non-ESM files)
// __dirname, __filename, require, module, exports
// Note: these are NOT truly global (they are module-scoped)
info

In Node.js, __dirname, __filename, require, module, and exports look like globals, but they are actually parameters injected into each module by the Node.js module wrapper. They are scoped to each file, not truly global.

Using the Global Object Responsibly (Avoid Polluting)

"Global namespace pollution" is the practice of adding too many variables and functions to the global scope, increasing the risk of naming collisions and making code harder to maintain.

The Problem with Global Pollution

Consider a web page that loads three scripts:

<script src="analytics.js"></script>
<script src="utils.js"></script>
<script src="app.js"></script>

If all three scripts use var to declare top-level variables:

// analytics.js
var data = fetchAnalyticsData();
var config = { trackClicks: true };

// utils.js
var config = { dateFormat: "YYYY-MM-DD" }; // Overwrites analytics config!
var data = []; // Overwrites analytics data!

// app.js
console.log(config); // { dateFormat: "YYYY-MM-DD" } (not what analytics expected!)

All three scripts share the same global scope. Variables from one script can silently overwrite variables from another. This was a massive problem in the pre-module era of JavaScript.

Rule 1: Use Modules

The best way to avoid global pollution is to use ES modules. Each module has its own scope, and nothing leaks to the global object unless explicitly exported:

<script type="module" src="analytics.js"></script>
<script type="module" src="utils.js"></script>
<script type="module" src="app.js"></script>
// analytics.js (module)
const data = fetchAnalyticsData(); // Scoped to this module
const config = { trackClicks: true }; // Not visible outside
export { data, config };

// utils.js (module)
const config = { dateFormat: "YYYY-MM-DD" }; // No conflict!
export { config };

// app.js (module)
import { config as analyticsConfig } from "./analytics.js";
import { config as utilsConfig } from "./utils.js";
// No conflicts (different names)

Rule 2: Use let and const, Never var at the Top Level

If you must write non-module scripts, use let and const instead of var. They do not create properties on the global object:

// This does NOT pollute window
let appState = { initialized: false };
const APP_VERSION = "2.0";

// Verify:
console.log(window.appState); // undefined
console.log(window.APP_VERSION); // undefined

Rule 3: Namespace Pattern (Pre-Module Legacy)

Before modules, the standard practice was to use a single global object as a namespace:

// Instead of many globals:
// var users = [];
// var config = {};
// function getUser() {}
// function setConfig() {}

// Use one global namespace:
var MyApp = MyApp || {};

MyApp.users = [];
MyApp.config = {};
MyApp.getUser = function(id) { /* ... */ };
MyApp.setConfig = function(key, value) { /* ... */ };

// Only "MyApp" is added to the global scope

You can nest namespaces for larger applications:

var MyApp = MyApp || {};
MyApp.Models = MyApp.Models || {};
MyApp.Views = MyApp.Views || {};
MyApp.Utils = MyApp.Utils || {};

MyApp.Models.User = function(name) {
this.name = name;
};

MyApp.Utils.formatDate = function(date) {
return date.toISOString();
};

Rule 4: Minimal Intentional Globals

Sometimes you genuinely need a global variable, perhaps for application-wide configuration, feature flags, or a library's public API. When you do, be explicit about it:

// GOOD: Explicit and intentional
globalThis.APP_CONFIG = Object.freeze({
apiUrl: "https://api.example.com",
environment: "production",
features: {
darkMode: true,
betaAccess: false
}
});

// Object.freeze prevents accidental modification
// APP_CONFIG.apiUrl = "hacked"; // Silently fails (or throws in strict mode)

Rule 5: Check Before Adding to Global Scope

When creating polyfills or library globals, always check if the name is already taken:

// Polyfill: only add if not already present
if (typeof globalThis.structuredClone !== "function") {
globalThis.structuredClone = function(value) {
return JSON.parse(JSON.stringify(value));
};
}

// Library: warn if name is already taken
if (typeof globalThis.MyLibrary !== "undefined") {
console.warn("MyLibrary is already defined! Possible conflict.");
}
globalThis.MyLibrary = { /* ... */ };

What NOT to Do

// DON'T: Create many top-level var variables
var userData = {};
var isLoggedIn = false;
var currentPage = "home";
var apiToken = "secret";
// All of these become window properties and can conflict

// DON'T: Forget to declare variables
function processItems(items) {
for (i = 0; i < items.length; i++) { // "i" leaks to global!
result = items[i] * 2; // "result" leaks to global!
}
}

// DON'T: Use window/global as a convenience storage
window.tempData = someComputation(); // Use a local variable or module instead

Checking for Global Pollution

You can check how many globals your code has added by comparing with a clean browser window:

// Run this in the console to find custom globals
(function() {
const iframe = document.createElement("iframe");
iframe.style.display = "none";
document.body.appendChild(iframe);

const cleanGlobals = Object.keys(iframe.contentWindow);
const currentGlobals = Object.keys(window);

const added = currentGlobals.filter(key => !cleanGlobals.includes(key));
console.log("Custom globals:", added);

document.body.removeChild(iframe);
})();

Summary

ConceptKey Takeaway
globalThisThe standardized, cross-environment reference to the global object (ES2020)
windowThe global object in browsers; also represents the browser window
globalThe global object in Node.js
var at top levelCreates a property on the global object
let/const at top levelDoes NOT create a property on the global object
Undeclared assignmentCreates a global property in non-strict mode (dangerous!)
Built-in globalsMath, JSON, console, parseInt, setTimeout, constructors, etc.
Global pollutionAdding too many names to the global scope, risking collisions
Best practiceUse ES modules, let/const, and strict mode; keep globals to an absolute minimum

The global object is a fundamental part of JavaScript, but in modern code, you should interact with it as little as possible. Use modules for code organization, let and const for variables, and globalThis only when you genuinely need cross-environment access to the global scope. The less your code depends on global state, the more predictable, testable, and maintainable it will be.