Javascript When to use “let” and when to use “var”

April 26, 2020
Written By Spida C

Exploring how creativity, culture, and technology connect us.

In many circumstances, let and var can seem to be used interchangeably. This, however, is not the case.

Here’s some great write-ups on stack overflow about the matter:

https://stackoverflow.com/questions/762011/whats-the-difference-between-using-let-and-var

The Short Answer

In modern JavaScript (ES6 and later), always use let or const. There is virtually no reason to use var in new code. The var keyword has quirky behavior that leads to bugs, and let/const were specifically designed to fix those problems.

Use const when the variable won’t be reassigned (most variables). Use let when you need to reassign the value (loop counters, accumulators, state that changes). Use var… never, unless you’re maintaining legacy code.

The Key Difference: Scope

The most important difference between var and let is scope:

  • var is function-scoped: it’s accessible anywhere within the function it’s declared in
  • let is block-scoped: it’s only accessible within the nearest enclosing block ({})

Here’s a practical example that shows why this matters:

// var leaks out of blocks
if (true) {
  var x = 10;
}
console.log(x); // 10 — var leaked out of the if block!

// let stays in its block
if (true) {
  let y = 10;
}
console.log(y); // ReferenceError — y is not defined

The var version creates a variable that exists outside the if block, which is almost never what you intend. This behavior is a common source of subtle bugs, especially in loops.

The Classic Loop Bug

This is the most famous var gotcha and a staple of JavaScript interviews:

// Bug with var
for (var i = 0; i < 3; i++) {
  setTimeout(() => console.log(i), 100);
}
// Output: 3, 3, 3 (not 0, 1, 2!)

// Fixed with let
for (let i = 0; i < 3; i++) {
  setTimeout(() => console.log(i), 100);
}
// Output: 0, 1, 2 (correct!)

With var, there’s only one i variable shared across all iterations. By the time the setTimeout callbacks execute, the loop has finished and i is 3. With let, each iteration gets its own copy of i. The MDN documentation on let explains this scoping behavior in detail.

Hoisting: Another Key Difference

Both var and let are “hoisted” (the JavaScript engine knows about them before your code runs), but they behave differently:

// var is hoisted and initialized to undefined
console.log(a); // undefined (no error)
var a = 5;

// let is hoisted but NOT initialized (Temporal Dead Zone)
console.log(b); // ReferenceError: Cannot access 'b' before initialization
let b = 5;

The var behavior silently gives you undefined instead of throwing an error, which can hide bugs. The let behavior (called the Temporal Dead Zone) is much safer — it immediately tells you when you’re trying to use a variable before it’s declared.

What About const?

const works like let (block-scoped, not hoisted to undefined) but cannot be reassigned after initialization:

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

// But objects/arrays can still be mutated!
const user = { name: 'Alice' };
user.name = 'Bob'; // This works! const prevents reassignment, not mutation

A common misconception is that const makes values immutable. It doesn’t — it only prevents reassignment of the variable itself. Object properties and array elements can still be modified.

Best Practices Summary

  • Default to const: Use it for any variable you won’t reassign (imports, configuration, computed values)
  • Use let for mutation: Loop counters, accumulators, values that change over time
  • Avoid var entirely: It exists only for backward compatibility with pre-ES6 code
  • Declare at the top of scope: Even though let/const are block-scoped, declaring them at the top of their scope improves readability

For more JavaScript fundamentals and web development tutorials, check out the GTWebs blog where we break down programming concepts for practical use.

Leave a Comment