let and const vs var

Acadestine

Learning Objectives
    • Differentiate between function scope and block scope.
    • Explain hoisting and the temporal dead zone.
    • Identify when to use let, const, or var.
    • Apply best practices in React components.

Understanding let and const vs var in JavaScript

Welcome! In this lesson, we'll explore the differences between var, let, and const — three ways to declare variables in JavaScript. Understanding these distinctions is crucial for writing clean, predictable, and bug-free React code.


Before ES6 (ECMAScript 2015), JavaScript only had var for variable declarations. ES6 introduced let and const to address common pitfalls. Today, modern JavaScript (and React) heavily favors let and const.

Note: const does not mean the value is immutable. It means the variable binding cannot be reassigned. For objects and arrays, their contents can still change.


Scope defines where a variable is accessible.

  • var is function-scoped: it is accessible anywhere inside the function it is declared in, regardless of block boundaries (like if or for).
  • let and const are block-scoped: they are only accessible within the nearest enclosing block { ... }.
// var – function scoped
function varExample() {
  if (true) {
    var x = 10;
  }
  console.log(x); // 10 (accessible outside the if block)
}
varExample();

// let / const – block scoped
function letExample() {
  if (true) {
    let y = 20;
    const z = 30;
  }
  console.log(y); // ReferenceError: y is not defined
  console.log(z); // ReferenceError: z is not defined
}
letExample();
Why block scope matters

Block scope prevents accidental variable leakage and makes code more predictable. In React, this is especially helpful inside event handlers, hooks, and conditional renders.


All variable declarations are hoisted (moved to the top of their scope during compilation), but their initialization behaves differently.

  • var: The declaration is hoisted and initialized with undefined. You can access the variable before its declaration (but get undefined).
  • let and const: The declaration is hoisted but not initialized. Accessing them before the declaration results in a ReferenceError because they are in a Temporal Dead Zone (TDZ).
// var hoisting
console.log(a); // undefined (no error)
var a = 5;

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

// const TDZ
console.log(c); // ReferenceError: Cannot access 'c' before initialization
const c = 15;

Warning: Relying on var hoisting can lead to subtle bugs. Always declare variables at the top of their scope.


  • var: Can be redeclared multiple times in the same scope without error.
  • let: Cannot be redeclared in the same scope.
  • const: Cannot be redeclared and cannot be reassigned after initialization.
// var redeclaration
var name = "Alice";
var name = "Bob"; // Allowed
console.log(name); // Bob

// let redeclaration
let age = 25;
let age = 30; // SyntaxError: Identifier 'age' has already been declared

// const redeclaration & reassignment
const PI = 3.14;
PI = 3.14159; // TypeError: Assignment to constant variable
const PI = 3.14; // SyntaxError: redeclaration

Use const by default. Only use let when you know the variable must be reassigned (e.g., loop counters, accumulators). Avoid var entirely in modern code.


In React components, you'll constantly work with variables. Here's how to choose:

  • const for:
  • Component declarations (function components).
  • Props destructuring.
  • State setters from useState.
  • Immutable values that never change.
  • let for:
  • Mutable values inside a component's logic (e.g., accumulators, temporary variables).
  • Avoid var – it has no advantage over let/const and introduces scope issues.
// React component example
const MyComponent = ({ initialCount }) => {
  const [count, setCount] = useState(initialCount); // const for state & setter

  let message = "No clicks yet"; // let because it may change
  if (count > 0) {
    message = `Clicked ${count} times`;
  }

  const handleClick = () => { // const for function
    setCount(count + 1);
  };

  return (
    <div>
      <p>{message}</p>
      <button onClick={handleClick}>Click me</button>
    </div>
  );
};

export default MyComponent; // const for export

  • var – function-scoped, hoisted with undefined, can be redeclared. Avoid.
  • let – block-scoped, hoisted but not initialized (TDZ), cannot be redeclared in the same scope. Use when reassignment is needed.
  • const – block-scoped, hoisted but not initialized, cannot be reassigned or redeclared. Use as the default.

Remember: In React, prefer const for almost everything, and use let only when you must mutate the binding.

Key Takeaway

"Use const by default. Use let when you need to reassign. Never use var."

Previous Lesson Next Lesson