A closure is a function defined within another scope that has access to all the variables within the outer scopeEric Elliot, EricElliottJS.com

In JavaScript, if you use the function keyword inside another function, you are creating a closure. Closures are the primary mechanism in JS to enable data privacy.

An example of a closure

function nameMe() {
  var name = 'Shane';
  function showName() {
     console.log(name);
  } 
  showName();
}

nameMe();

The variables within a closure are still acessible after the function has been returned. For example user1 can access their data - as it existed when the closure was created when personInfo was called - at any time. You are unable to get/access data from outside the scope, but can access what you need within the closure.

const personInfo = (a, b) => {
  const obj = {}
  const name = a;
  const DOB = b;
  return {
    registered: () => {
      return `${name} is registered`;
    },
    sayAge: () => {
      return DOB;
    }
  }
}

const user1 = personInfo('Shane', 1986);
console.log(user1.registered());
console.log(user1.sayAge());

// Undefined
console.log(user1.DOB);

Uses of closures

Self invoking function (IIFE)

In the following example btnCount self-invokes, returning a function expression.

<button onClick="btnCount()">Btn 2</button>
const btnCount = (() => {
  let count = 0;
  return () => {
    ++count;
    console.log(count);
  }
})();

ES6 IIFE

As a rule of thumb you want to avoid using IIFEs in ES6, as there are other way to handle global variable polution.

IIFE was one of the most used patterns in the ES5 standard, as functions were the only way to declare a scoped block of code. So the following code will result with a ReferenceError:

(function() {
    var scoped = 42;
}());

console.log(scoped); // ReferenceError

ECMAScript introduced the block scoped let and const, so instead of using an IIFE, we can have the following code:

{
    let scoped = 42;
}

console.log(scoped); // ReferenceError

IIFEs were used as a building block in the revealing module pattern. Instead of using this pattern, with ES6 we can use modules. Modules declare their own scope and variables created inside the module will not polute the global object:

// myModule.js

let counter = 0;

export function increment() {
    counter++;
}    

// logic.js

import {increment} from 'myModule.js';

increment();

Function Factories

One powerful use of closures is to use the outer function as a factory for creating functions that are somehow related.

const sayname = (title) => {
  return (name) => {
    return `Hi ${title} ${name}`;
  }
};

const doctors = sayname('Dr')
// Hi Dr James Smith
console.log(doctors('James Smith'));

Namespacing

Making public and private methods by using a IIFE to make a closure.

const test = (() => {
  let privateNumber = 100;
  return {
    sayNumber: () => {
      return privateNumber;
    }
  }
})();

// 100
console.log(test.sayNumber());
// Undefined
console.log(test.privateNumber);

Check out this excellent analogy on Stack Overflow.

Refs