Course topics

By WebNest Studio Engineering Team

JavaScript Tutorial

JavaScript Variables: var, let, and const

Variables are named containers for values that a program can create, read, and update. Modern JavaScript provides three ways to declare a variable — var, let, and const — and each behaves differently in terms of scope, hoisting, and whether reassignment is allowed.

Understanding the differences between these three keywords is one of the most important early steps in learning JavaScript, because using the wrong one is a frequent source of confusing bugs, especially inside loops and conditional blocks.

Why it matters

There are three ways to declare a variable in JavaScript, and choosing the wrong one causes real bugs: var leaks out of blocks and can be used before it is assigned. Modern code uses const by default and let when a value must change, and interviewers ask about the differences in nearly every JavaScript interview.

var — Function-Scoped and Hoisted

var is the original way to declare variables in JavaScript. A variable declared with var is scoped to the nearest enclosing function (or the global scope if declared outside any function) — not to the block ({ }) it appears in. var declarations are also "hoisted": the declaration is moved to the top of its scope during compilation, but the value is not, so the variable exists as undefined until the line where it is assigned actually runs.

let — Block-Scoped and Reassignable

let declares a variable scoped to the nearest enclosing block, such as an if block, a for loop, or any pair of curly braces. Like var, a let variable can be reassigned after declaration, but unlike var, accessing it before its declaration line throws a ReferenceError rather than silently returning undefined — this gap is called the "temporal dead zone."

const — Block-Scoped and Not Reassignable

const behaves exactly like let in terms of scoping and the temporal dead zone, but a const variable cannot be reassigned after its initial value is set, and it must be initialized at the point of declaration. Importantly, const only prevents reassigning the variable itself — if the value is an object or array, its contents can still be mutated.

Choosing Between Them

Modern JavaScript style strongly favors const by default, switching to let only when a variable genuinely needs to be reassigned, and avoiding var almost entirely in new code because of its confusing function-scoping and hoisting behavior.

  • const — default choice; value binding never changes.
  • let — used when the variable will be reassigned, such as a loop counter or an accumulator.
  • var — legacy keyword, generally avoided in modern code except when maintaining older codebases.

Examples

var leaking out of a block versus let staying scoped to it

JavaScript
if (true) {
  var leaked = "I am visible outside the block";
  let contained = "I am only visible inside the block";
}

console.log(leaked);
console.log(typeof contained);
Output
I am visible outside the block
undefined

Hoisting behavior: var is undefined before assignment, let/const throw in the temporal dead zone

JavaScript
console.log(hoistedVar); // no error, just undefined
var hoistedVar = "assigned later";

try {
  console.log(hoistedLet);
  let hoistedLet = "assigned later";
} catch (error) {
  console.log(error.message);
}

const PI = 3.14159;
// PI = 3; // Uncommenting this line throws: Assignment to constant variable.
console.log(PI);
Output
undefined
Cannot access 'hoistedLet' before initialization
3.14159

Common Mistakes

  • Declaring a loop counter with "var" inside a for loop and being surprised that all callbacks created in the loop see the same final value instead of a per-iteration value.
  • Trying to reassign a "const" variable and being confused by the resulting TypeError, when "let" was actually the correct choice.
  • Assuming "const" makes an object or array fully immutable — it only locks the variable binding, not the object's contents.
  • Reading a "let" or "const" variable before its declaration line and not recognizing the resulting ReferenceError as the temporal dead zone.

Exercise

The code fails because total is declared with const but is changed, and the loop counter declared with var remains visible after the loop. Choose the right keyword for each so that the total is printed and the counter no longer exists outside the loop.

Expected output: 6 then undefined

JavaScript · starter code
const total = 0;

for (var i = 1; i <= 3; i++) {
  total += i;
}

console.log(total);
console.log(typeof i); // should print "undefined": i must not exist out here
Show hints
  • A value that is reassigned must be declared with let.
  • let is scoped to the block, so a loop counter declared with it does not exist after the loop.
Show solution
JavaScript · solution
let total = 0;

for (let i = 1; i <= 3; i++) {
  total += i;
}

console.log(total);
console.log(typeof i); // should print "undefined": i must not exist out here

Quick quiz

1. What happens when a const variable is reassigned?

  • A. A TypeError is thrown
  • B. The new value is stored
  • C. The assignment is ignored silently
  • D. It becomes a let
Show answer

A. A const binding cannot be reassigned after it is initialised.

2. Given const user = { name: "Asha" }; is user.name = "Ravi"; allowed?

  • A. No, const makes the object immutable
  • B. Yes; const prevents reassigning the variable, not changing the object
  • C. Only in strict mode
  • D. It throws a SyntaxError
Show answer

B. To make an object itself unchangeable, use Object.freeze.

3. What does console.log(x); var x = 5; print?

  • A. It throws a ReferenceError
  • B. 5
  • C. undefined
  • D. null
Show answer

C. The var declaration is hoisted, but the assignment stays where it is.

Interview questions

What are the differences between var, let and const?

Show answer

var is function-scoped, is hoisted and initialised to undefined, and can be redeclared. let and const are block-scoped, are hoisted but cannot be used before their declaration, and cannot be redeclared in the same scope. let can be reassigned; const cannot, and must be given a value when declared. Use const by default and let only when the value changes.

What is the temporal dead zone?

Show answer

It is the part of a block between its start and the line where a let or const variable is declared. The variable exists in that region, because the declaration is hoisted, but reading or writing it throws a ReferenceError. This catches the mistake of using a variable before it has a value, which var allows silently by returning undefined.

Key Points to Remember

  • "var" is function-scoped and hoisted with an undefined initial value; "let" and "const" are block-scoped.
  • "let" and "const" are hoisted too, but remain inaccessible until their declaration line (the temporal dead zone).
  • "const" prevents reassigning the variable, not mutating the object or array it refers to.
  • Prefer "const" by default, "let" when reassignment is needed, and avoid "var" in new code.

Practice in the playground

Write and run your own code for this topic, or start from the exercise or an example. Shows a live preview of your HTML, CSS and JavaScript. Your code for each topic is kept in this browser.

Run the examples

Change an input, predict the result, then compare it with the output. Explain why the result changes.

WebNest Studio

Written by

WebNest Studio Engineering Team

Practical lessons from developers working with Java, Python, React, databases and production systems.

Led by Vansh Duggal, Founder, WebNest Studio · Full-stack & software engineering