Leo Cristofani · Web Developer

Why you should understand closure in Javascript

Definitely NOT because it’s a common interview question, but because it’s one of the most useful and powerful features of Javascript.

Every time a function is invoked, the Javascript engine creates a brand new execution context with memory that goes away as soon as the function finishes executing, and is removed from the call stack.

Closure makes it possible for a function to have persisting state. This feature alone enables memoization, partial application, the module pattern and React Hooks, to name a few.

In simple terms, let’s say that in order for a function to have persisting state, it must be created and returned from another function. Let’s look at a simple example:

function makeCounter() {
  let count = 0
  return function counter() {
    return count++
  }
}

const counter = makeCounter()

counter() // 0
counter() // 1
counter() // 2

Note that count is persisted between function calls, and the counter function still has a reference to it even after makeCounter has finished executing.

Now that we know how to persist state between function calls, let’s look at a more useful use of closure. Let’s create a simplified history feature so users can optionally undo actions on an application.

function makeHistory(limit) {
  function makeStack() {
    // note that both push and pop have a persiting ref. to data
    const data = []

    function push(action) {
      if (data.length < limit) {
        data.unshift(action)
      }
    }

    function pop() {
      return data.length === 0 ? undefined : data.shift()
    }

    return { push, pop }
  }

  const history = makeStack()

  // act has a persisting reference to history
  return function act(action) {
    if (action === "undo") {
      const popped = history.pop()
      return popped ? `${popped} undone` : "nothing to undo"
    }
    history.push(action)
    return `${action} done`
  }
}

const act = makeHistory(2)

act("get") // 'get done'
act("undo") // 'get undone'
act("create") // 'create done'
act("update") // 'update done'
act("delete") // 'delete done'
act("undo") // 'update undone'
act("undo") // 'create undone'
act("undo") // 'nothing to undo'

Thanks for reading! Have something to say? Please, leave a comment!