Using closures

January 20, 2019
3 minute read
0 claps
javascript
Jump to Section

When I was learning about closures in JavaScript for the first time I saw a lot of examples like this:

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

console.log(counter()) //1
console.log(counter()) //2
console.log(counter()) //3

Now, it was pretty clear to me what was happening; the outer function (which is an Immediately Invoked Function Expression or IIFE for short) declares the count variable, assigns the number zero to it and then returns the inner function. This inner function is executed each time we call count() and 'knows' about the count variable because it has closure over it.

So all well and good. The bit that was not clear to me was why this would be useful! As such, I would like to demonstrate a couple of ways in which I use closures in my daily coding.

Example one

The first technique is encapsulation. This is a way of creating a module where the inner workings are private and only certain methods are exposed for other modules to interact with them. It is exactly what is happening in the example above but it is (hopefully!) easier to see why it is useful when we look at some code which has a bit more going on.

const library = (function() {
  const books = ['Island', '1984', 'Dracula', 'Papillon']

  return {
    getBooks() {
      return [...books]
    },
    deleteBook(title) {
      books.splice(books.indexOf(title), 1)
    },
    addBook(title) {
      books.push(title)
    },
  }
})()

library.addBook('catch 22')
library.deleteBook('Dracula')
console.log(library.getBooks()) // [ Island, 1984, Papillon, catch 22 ]

const libraryBooks = library.getBooks()
libraryBooks.push('Beowulf')
console.log(libraryBooks) // [ Island, 1984, Papillon, catch 22, Beowulf ]
console.log(library.getBooks()) // [ Island, 1984, Papillon, catch 22 ]

As you can see, our books array is protected from the outside world by the inner function's closure over it. The only way to interact with it is through the public methods; getBooks() returns a copy of the array instead of a reference to it and books can only be added or deleted one at a time.

Example two

The second example is a pattern I use frequently. I will use a React component to demonstrate, don't worry if you don't know React, it is pretty easy to see what is happening.

class StartEndDate extends React.Component {
  state = {
    start: null,
    end: null
  }

  // This is our closure, I have used es6 arrow functions this time
  updateTime = startOrEnd => newTime => (
    this.setState({
      [startOrEnd]: newTime
    })
  )

  render() {
    return (
      <DateInput label="From" updateTime={this.updateTime('start')} />
      <DateInput label="To"   updateTime={this.updateTime('end')} />
    )
  }
}

function DateInput({ label, updateTime }) {
  return (
    <label for="timeInput">From</label>
    <input id="timeInput" type="time" onChange={updateTime}>
  )
}

In this code we have one stateful React component, which is declared as an es6 class and one functional component. You should be able to see where the functional component is used, it is in the return of the render method (the code that looks like HTML is actually JSX; it calls the DateInput function, passing the props label and updateTime to it).

The DateInput function returns the markup for a <label> and <input>. When a change event is detected, the value is passed through to the updateTime method on the StartEndDate class.

If you look at the render method where this function is passed to DateInput, it is first called with either the value "start" or "end". Our two inputs now have their own version of the updateTime method which has closure over the startOrEnd variable. Using computed property keys we can dynamically assign the new value to the component's state using the variable in closure.


These are two of my most often used closure patterns. I hope that I have been able to show why they are such a useful feature of the language and an important tool to have in your tool-set.

If you've found this helpful then let me know with a clap or two!

Using React Hooks with Class Components
Semantic versioning with NPM