HomebaseWorks
Lesson 1 of 4

Scope, hoisting and closures in JavaScript

How var, let and const differ, what hoisting really does, and why closures inside loops behave as they do.

EWritten by the HomebaseWorks editorial team · reviewed 26 Oct 2026

Most JavaScript output questions test one thing: where a variable lives and when it gets its value. Learn the rules for var, let and const, and the classic puzzles become routine.

Advertisement

var, let and const

  • var is function-scoped. A var declared inside an if block is visible in the whole function.
  • let and const are block-scoped, so they exist only inside the nearest pair of braces.
  • const stops the variable from being reassigned, but it does not freeze the object it points to.
const user = { name: "Asha" };
user.name = "Ravi";   // allowed
user = {};            // TypeError: Assignment to constant variable.

Hoisting

Before code runs, declarations are registered in their scope. A var is created and set to undefined, so reading it early gives undefined. A let or const is also registered, but it stays in the temporal dead zone until its line runs, and reading it early throws a ReferenceError.

console.log(a);   // undefined
var a = 1;

console.log(b);   // ReferenceError
let b = 2;

Function declarations are hoisted together with their body, so you can call them before the line where they appear. Function expressions assigned to a variable follow that variable's rules.

Closures

A closure is a function that remembers the variables from the scope where it was created, even after that scope has finished running.

function makeCounter() {
  let count = 0;
  return function () { count++; return count; };
}
const next = makeCounter();
next();   // 1
next();   // 2

The loop puzzle follows from this. With var i, every callback shares one variable, so timers created in a loop all see its final value. With let i, each iteration gets its own binding, so the callbacks log 0, 1 and 2.

Checklist before answering

  1. Find the declaration keyword for each variable.
  2. Decide its scope: function or block.
  3. Check whether the line reads it before or after its declaration.
  4. For callbacks, ask which binding they captured.
Advertisement
Continue with JavaScript4 lessons · 1 interview set · 1 test · 1 certificate
Not tested

More in Programming