"I was reviewing a pull request where a globally declared var name = 'auth' broke our third-party map integration."
The external API relied on a global window.name attribute, which our local code accidentally overwrote because of var's relationship with the global window object. That is when I decided to outline the differences between var, let, and const clearly.
Declaring variables is the first thing we learn in JavaScript. But the choice between var, let, and const goes beyond simple syntax preferences. It directly impacts memory leak vulnerabilities, scoping errors, and interactions with the global browser workspace.
This guide breaks down exactly how variables are scoped, how they interact with the browser's window object, and how hoisting can introduce silent runtime errors.
02. The Window Object Relationship
In browser environments, the global context is represented by the window object.
When you declare a variable with var in the global scope (outside of any function), it is **automatically assigned as a property** on the window object.
Global Var Binding
var message = "I am global!";
console.log(message); // "I am global!"
console.log(window.message); // "I am global!" (Bound to window)
Global Let and Const Separation
Global variables declared with let or const behave differently. They are globally scoped and accessible in your code, but they **do not** bind as properties on the window object:
let testLet = "Active let";
const testConst = "Active const";
console.log(window.testLet); // undefined
console.log(window.testConst); // undefined
This is a critical safety feature. Binding variables to the window object risks collision with other scripts, libraries, or global browser APIs.
03. Block Scope vs. Function Scope
Variables declared with var are **function-scoped**. They ignore blocks like if blocks, for loops, or switch blocks, and leak into the surrounding scope.
Variables declared with let and const are **block-scoped**, meaning they are strictly bound to the block (demarcated by curly braces {}) where they are declared.
Scoping Comparison Example
if (true) {
var variableOne = "I am a var";
let variableTwo = "I am a let";
}
console.log(variableOne); // "I am a var" (Leaked out of the block)
console.log(variableTwo); // ReferenceError: variableTwo is not defined
04. Hoisting and the Temporal Dead Zone
In JavaScript, variable declarations are "hoisted" to the top of their scope during compilation.
- var hoisting:
varis hoisted and automatically initialized asundefined. You can reference it before the line it is declared on without a crash. - let and const hoisting: These are hoisted but not initialized. They exist in a Temporal Dead Zone (TDZ) from the start of the block until the declaration line. Accessing them before initialization throws a
ReferenceError.
Hoisting Example
console.log(hoistedVar); // Outputs: undefined
var hoistedVar = "Success";
console.log(hoistedLet); // ReferenceError: Cannot access 'hoistedLet' before initialization
let hoistedLet = "Success";
05. Mutability and Const Reassignment
Variables declared with const cannot be reassigned. However, the value of a const variable is not necessarily immutable.
If a const variable holds an object or an array, you can modify its properties or elements:
const user = { name: "Ramkumar" };
user.name = "Khubchandani"; // Allowed: Modifying a property
console.log(user.name); // "Khubchandani"
// Throws TypeError: Assignment to constant variable.
user = { name: "Test" };
06. Scoping Best Practices
To write reliable, modern JavaScript:
Use const by default for variables that do not need to be reassigned.
Use let for loop counters or variables that require reassignment.
Avoid var entirely to prevent global window object pollution and bugs related to block leakage and hoisting.
To test your skills in managing JavaScript scope and variables, explore our [INTERNAL LINK: frontend coding challenges], or join our [INTERNAL LINK: React Masterclass learning path]. You can also book [INTERNAL LINK: 1:1 expert mentorship sessions] with our senior engineers to audit your application structure.
07. Frequently Asked Questions
Why does var bind to the window object in browsers?
This behavior dates back to JavaScript's initial design, where all global declarations were treated as properties of the global object. When ES6 introduced let and const, they were designed to exist in a separate declarative environment record to prevent namespace pollution.
Can you freeze a const object to make it immutable?
Yes, you can use Object.freeze(obj). Once frozen, you cannot add, delete, or modify properties on the object.
Are let and const hoisted?
Yes, let and const are hoisted to the top of their block, but they are not initialized. They remain in the Temporal Dead Zone (TDZ) until execution reaches their declaration line, and accessing them before that throws a ReferenceError.