js

Var, Let, Const in JavaScript

4 min read
Var, Let, Const in JavaScript
Var, Let, Const Demo

Open this example in our interactive code editor to experiment with it.

Try the Editor

Introduction

Variables are the building blocks of any JavaScript program. They let you store and manipulate data. But JavaScript has three ways to declare variables - var, let, and const - and each behaves differently.

Understanding these differences is crucial for writing clean, bug-free code. In this article, we’ll explore each keyword, their scope rules, hoisting behavior, and when to use which.

Variables

Global Variables

Before we look at var, let, and const, let’s understand global variables. Any variable declared outside of a function (without a keyword, or with var at the top level) becomes a global variable:

// Global variable - accessible everywhere
myGlobal = "I'm global";

function greet() {
  console.log(myGlobal); // "I'm global"
}

greet();
console.log(myGlobal); // "I'm global"

Global variables attach to the window object in browsers:

var globalVar = "Hello";

console.log(window.globalVar); // "Hello"
console.log(globalVar); // "Hello"

Warning: Avoid global variables whenever possible. They can lead to naming collisions, make debugging harder, and create unpredictable behavior when multiple scripts modify the same variable.

Var

var is the original way to declare variables in JavaScript (ES5 and earlier). It has function scope - meaning it’s scoped to the nearest function, not the nearest block:

function example() {
  var x = 10;

  if (true) {
    var x = 20; // Same variable! Not a new one.
    console.log(x); // 20
  }

  console.log(x); // 20 - changed by the if block
}

example();

var can also be redeclared without errors:

var name = "Alice";
var name = "Bob"; // No error!
console.log(name); // "Bob"

// This can lead to accidental overwrites
// in large codebases

Var hoisting: Variables declared with var are hoisted to the top of their scope. This means you can reference them before the declaration, but they’ll be undefined:

console.log(hoisted); // undefined (not an error!)
var hoisted = "I'm hoisted";
console.log(hoisted); // "I'm hoisted"

// JavaScript interprets this as:
// var hoisted;
// console.log(hoisted); // undefined
// hoisted = "I'm hoisted";
// console.log(hoisted); // "I'm hoisted"

The fix is simple - always declare variables before using them:

var hoisted = "I'm hoisted";
console.log(hoisted); // "I'm hoisted"

Let

let was introduced in ES6 (ES2015) and is the modern replacement for var. It has block scope - meaning it’s scoped to the nearest curly braces {}:

function example() {
  let x = 10;

  if (true) {
    let x = 20; // Different variable!
    console.log(x); // 20
  }

  console.log(x); // 10 - unchanged
}

example();

let cannot be redeclared in the same scope:

let name = "Alice";
// let name = "Bob"; // SyntaxError: Identifier 'name' has already been declared

But it can be reassigned:

let count = 0;
count = 1; // This is fine
count = 2; // This is fine too
console.log(count); // 2

Let hoisting: let is technically hoisted, but it’s placed in a Temporal Dead Zone (TDZ) from the start of the block until the declaration. Accessing it before the declaration throws an error:

// console.log(x); // ReferenceError: Cannot access 'x' before initialization
let x = 10;
console.log(x); // 10

This is actually a good thing - it catches bugs that var would silently ignore.

Const

const also has block scope like let, but with one key difference: the binding is constant. You can’t reassign a const variable:

const PI = 3.14159;
// PI = 3.14; // TypeError: Assignment to constant variable

const name = "Alice";
// name = "Bob"; // TypeError: Assignment to constant variable

However, const does not make objects or arrays immutable. You can still modify their contents:

const user = { name: "Alice", age: 25 };
user.age = 26; // This is fine!
console.log(user); // { name: "Alice", age: 26 }

// But you can't reassign the variable itself:
// user = { name: "Bob" }; // TypeError

const colors = ["red", "green"];
colors.push("blue"); // This is fine!
console.log(colors); // ["red", "green", "blue"]

// But you can't reassign:
// colors = ["yellow"]; // TypeError

If you need a truly immutable object, use Object.freeze():

const frozenUser = Object.freeze({ name: "Alice", age: 25 });
frozenUser.age = 26; // Silently fails (or throws in strict mode)
console.log(frozenUser.age); // 25 - unchanged

Avoiding global scope

Global variables are one of the most common sources of bugs. Here are some tips to avoid them:

  • Always use const or let to declare variables - never rely on implicit global creation
  • Use modules (ES6 import/export) to encapsulate code
  • Use IIFEs (Immediately Invoked Function Expressions) in legacy code to create scope
  • Enable strict mode ("use strict") which throws an error when you accidentally create globals
  • Use a linter like ESLint with the no-undef and no-var rules
  • Keep functions small and focused - fewer variables in scope means fewer conflicts

Summary

Here’s a quick reference for when to use each keyword:

  • const - Use by default for all variables. It communicates that the binding won’t change and prevents accidental reassignment
  • let - Use when you need to reassign a variable (loop counters, accumulators, conditional assignments)
  • var - Avoid in modern JavaScript. It has confusing scoping rules and is hoisted in ways that can cause bugs

The general rule is: use const everywhere, and only switch to let when you need to reassign. Never use var.

Featurevarletconst
ScopeFunctionBlockBlock
HoistingYes (undefined)Yes (TDZ)Yes (TDZ)
RedeclarationAllowedNot allowedNot allowed
ReassignmentAllowedAllowedNot allowed
Best forLegacy codeMutable valuesEverything else

Closing Notes

Understanding var, let, and const is fundamental to writing good JavaScript. While var was the only option for many years, the introduction of let and const in ES6 gave us better tools for managing variable scope and preventing bugs.

If you’re working with a modern codebase, you should almost never need var. Set up ESLint with the no-var rule and let the tooling enforce this for you.

For more JavaScript fundamentals, check out the MDN documentation on variable declarations.

Ready to level up your coding skills?

Build real projects and grow your portfolio with BigDevSoon.

Start 7-Day Free Trial
Adrian Bigaj
Adrian Bigaj

Creator of BigDevSoon

Full-stack developer and educator passionate about helping developers build real-world skills through hands-on projects. Creator of BigDevSoon, a vibe coding platform with 21 projects, 100 coding challenges, 40+ practice problems, and Merlin AI.