Explain the differences between var, let, and const. When should you use each?

4 minintermediatejavascriptdifferencesvarletconst

Quick Answer

The three variable declaration keywords in JavaScript have different scoping rules, hoisting behavior, and mutability characteristics.

Detailed Answer

Explain the differences between var, let, and const. When should you use each?

Answer: The three variable declaration keywords in JavaScript have different scoping rules, hoisting behavior, and mutability characteristics.

Key Differences:

Featurevarletconst
ScopeFunction-scopedBlock-scopedBlock-scoped
HoistingHoisted and initialized with undefinedHoisted but not initialized (TDZ)Hoisted but not initialized (TDZ)
Re-declarationAllowedNot allowedNot allowed
Re-assignmentAllowedAllowedNot allowed
Temporal Dead ZoneNoYesYes

1. Scope Differences:

// var - function scoped
function example() {
  if (true) {
    var functionScoped = 'I am function scoped';
  }
  console.log(functionScoped); // Works - accessible outside block
}

// let/const - block scoped
function example() {
  if (true) {
    let blockScoped = 'I am block scoped';
    const alsoBlockScoped = 'I am also block scoped';
  }
  console.log(blockScoped); // ReferenceError: blockScoped is not defined
  console.log(alsoBlockScoped); // ReferenceError: alsoBlockScoped is not defined
}

2. Hoisting Behavior:

// var - hoisted and initialized with undefined
console.log(varVariable); // undefined (not ReferenceError)
var varVariable = 'Hello';

// let/const - hoisted but in Temporal Dead Zone
console.log(letVariable); // ReferenceError: Cannot access 'letVariable' before initialization
let letVariable = 'Hello';

console.log(constVariable); // ReferenceError: Cannot access 'constVariable' before initialization
const constVariable = 'Hello';

3. Re-declaration:

// var - allows re-declaration
var name = 'John';
var name = 'Jane'; // No error
console.log(name); // 'Jane'

// let - does not allow re-declaration
let age = 25;
let age = 30; // SyntaxError: Identifier 'age' has already been declared

// const - does not allow re-declaration
const city = 'NYC';
const city = 'LA'; // SyntaxError: Identifier 'city' has already been declared

4. Re-assignment:

// var and let - allow re-assignment
var count = 0;
count = 1; // Works

let total = 10;
total = 20; // Works

// const - does not allow re-assignment
const PI = 3.14159;
PI = 3.14; // TypeError: Assignment to constant variable

5. Temporal Dead Zone (TDZ):

// TDZ for let and const
function tdzExample() {
  console.log(typeof x); // ReferenceError: Cannot access 'x' before initialization
  let x = 10;
}

// var does not have TDZ
function noTdzExample() {
  console.log(typeof y); // 'undefined'
  var y = 10;
}

When to Use Each:

Use const by default:

// ✅ Use const for values that won't change
const API_URL = 'https://api.example.com';
const MAX_RETRIES = 3;
const user = { name: 'John', age: 30 };

// const with objects/arrays - you can modify contents
const users = [];
users.push({ name: 'Jane' }); // Works - modifying array contents
// users = []; // Error - cannot reassign the array reference

const config = { theme: 'dark' };
config.theme = 'light'; // Works - modifying object properties
// config = {}; // Error - cannot reassign the object reference

Use let when you need to reassign:

// ✅ Use let when value needs to change
let currentUser = null;
let isLoading = false;
let counter = 0;

// In loops
for (let i = 0; i < 10; i++) {
  setTimeout(() => console.log(i), 100); // Each i is block-scoped
}

// In conditionals
let result;
if (condition) {
  result = 'success';
} else {
  result = 'failure';
}

Avoid var (legacy):

// ❌ Avoid var in modern JavaScript
var oldStyle = 'avoid this';

// Problems with var:
// 1. Function scoping can be confusing
for (var i = 0; i < 3; i++) {
  setTimeout(() => console.log(i), 100); // Prints 3, 3, 3
}

// 2. Hoisting can lead to unexpected behavior
console.log(hoisted); // undefined (not ReferenceError)
var hoisted = 'I am hoisted';

// 3. Re-declaration can cause bugs
var name = 'John';
// ... 100 lines later ...
var name = 'Jane'; // Accidentally overwrites previous declaration

Modern Best Practices:

// ✅ Modern approach
const DEFAULT_CONFIG = {
  apiUrl: 'https://api.example.com',
  timeout: 5000
};

function processData(data) {
  const results = [];
  let hasErrors = false;
  
  for (const item of data) {
    try {
      const processed = transformItem(item);
      results.push(processed);
    } catch (error) {
      hasErrors = true;
      console.error('Processing error:', error);
    }
  }
  
  return { results, hasErrors };
}

// ✅ Use const for function declarations
const calculateTotal = (items) => {
  return items.reduce((sum, item) => sum + item.price, 0);
};

// ✅ Use const for imported modules
import { useState, useEffect } from 'react';
const MyComponent = () => {
  const [count, setCount] = useState(0);
  // ...
};

Summary:

  • const: Use by default for all variables that won't be reassigned
  • let: Use when you need to reassign the variable
  • var: Avoid in modern JavaScript due to confusing scoping and hoisting behavior