ToolPopToolPop
JavaScript · Lesson 3 of 18

Functions, arrow functions, and the closure that remembers

11 min readUpdated 24 Jun 2026

Functions are how JavaScript moves. You write a small piece of logic once, give it a name, and call it from anywhere. Sounds boring, except JavaScript gives you three syntaxes for the same idea and one of them quietly changes how this works.

Then there is the closure question, which gets asked in every junior interview. We will fix that too.

Diagram
rendering diagram...
A closure is just a function that remembers its outer variables

Three ways to write a function

js
function add(a, b) { return a + b; }        // declaration
const sub = function (a, b) { return a - b; }; // expression
const mul = (a, b) => a * b;                // arrow
  • Declarations get hoisted. You can call add() before the line where it is defined.
  • Expressions are values assigned to a variable. No hoisting, normal scoping rules.
  • Arrow functions are short, return implicitly when there is no body braces, and do not bind their own this.

In modern code, arrow functions are the default for short callbacks. Declarations are still nice for top-level named utilities.

The this problem

this in JavaScript refers to "the object the function was called on." With arrow functions, this comes from the enclosing scope instead.

js
const cart = {
  items: ['samosa', 'chai'],
  showRegular() { setTimeout(function () { console.log(this.items); }, 100); },
  showArrow()   { setTimeout(() => console.log(this.items), 100); },
};

showRegular logs undefined. The inner function loses its this. showArrow works, because the arrow inherits this from cart. This single fact is why arrows took over callbacks.

If you are reading old code with a lot of var self = this;, that is the pre-arrow workaround.

Closures, the chai-stall way

Imagine a chai stall in Indiranagar. The owner keeps a cash-box behind the counter. Customers never touch it. They place an order, the owner adds to the box, and at the end of the day the box has the total.

A closure is the same idea. A function returns another function that secretly keeps access to a variable from its parent.

js
function makeCashBox() {
  let total = 0;
  return function add(amount) {
    total = total + amount;
    return total;
  };
}
 
const stall = makeCashBox();
stall(10); // 10
stall(20); // 30

total is hidden. Nothing outside makeCashBox can read or change it. The returned function still has the key. That is a closure.

Where you will actually use closures

  • Counters and IDs where state needs to persist between calls.
  • Private data in modules, before classes were popular.
  • Memoization, caching results of expensive calls.
  • Event handlers that need to remember which button they belong to.

Every callback you write in addEventListener, map, setTimeout is a closure. You have been using them without knowing it.

A small recap

  • Three ways to write a function. Pick arrow for short callbacks, declaration for named utilities.
  • Arrow functions do not have their own this. That is a feature, not a bug.
  • Closures are functions that remember the variables they grew up with.
  • You use closures in almost every line of modern JS, even if nobody told you.

Next up: arrays and objects, the two data shapes you will use every single day.

Free tools you can use while you learn

Chai0/2 done

Watching quietly. Tap me if you want a tip.

JS Playground
console
// hit run to see output

Try this (0 of 2 done)

  1. 1

    Write an arrow function `double` that returns its arg times 2. Log double(7).

    show answer
    const double = (n) => n * 2;
    console.log(double(7));
  2. 2

    Build a counter that starts at 100. Call it twice and log both values.

    hint

    Same closure pattern, just initialise count = 100.

    show answer
    function counter(start) {
      let n = start;
      return () => ++n;
    }
    const c = counter(100);
    console.log(c(), c());