Whenever I searched for an example of what a JavaScript closure is, I would always run into something like this:

const multiplier = (factor) => {

return ((value) => {

return factor * value;

});

}; const doubler = multiplier(2); console.log(doubler(9)); // 18

This does a textbook job of displaying the infrastructure of what a JavaScript closure is, showing that multiplier returns a frozen function where the function retains its outer scope’s variable — in this case the factor variable.

Though any time I looked at examples like this above, I could not help but wonder why one wouldn’t do something like this instead:

const product = (num1, num2) => {

return num1 * num2;

} console.log(producut(2, 9)); // 18

It really wasn’t until I started looking into closure and privacy, that I realized how useful and important closures are in JavaScript.

Example: Employee Registration

Suppose we were put in charge of keeping track of all the employees in a brand new start-up. Leveraging some Object-Oriented Design, we put together this block of code.

let employeeId = 0; class Employee {

constructor(name, role) {

this.name = name;

this.role = role;

this.id = ++employeeId;

}

} const kevin = new Employee('Kevin', 'Developer');

const george = new Employee('George', 'HR'); console.log(kevin);

// Employee { name: 'Kevin', role: 'Developer', id: 1 } console.log(george);

// Employee { name: 'George', role: 'HR', id: 2 } console.log(employeeId); //2

This works decently, but our employeeId is exposed out in the wilderness and vulnerable to getting easily overwritten!

For example, we could assign employeeId to something completely random, and our next employee’s id is going to look rather silly.

employeeId = 'gibberish';

const jerry = new Employee('Jerry', 'Sales');

console.log(jerry);

// Employee { name: 'Jerry', role: 'Sales', id: NaN }

Enter Closure

To get around this issue, we can leverage closure and sandwich our employeeId variable like so:

function createEmployee() {

let employeeId = 0;

return class {

constructor(name, role) {

this.name = name;

this.role = role;

this.id = ++employeeId;

}

}

} const Employee = createEmployee();

At this point, our employeeId variable is closed off from outside of createEmployee() but accessible inside of the function that createEmployee() returns.

const kevin = new Employee('Kevin', 'Developer');

const george = new Employee('George', 'HR'); console.log(kevin);

// Employee { name: 'Kevin', role: 'Developer', id: 1 } console.log(george);

// Employee { name: 'George', role: 'HR', id: 2 } console.log(employeeId);

// ReferenceError: employeeId is not defined

Now, even if we assign our employeeId value outside of the createEmployee() function, this will not corrupt our employee creating function that we wrote up.

employeeId = 'gibberish';

// this employeeId !== employeeId inside createEmployee() const jerry = new Employee('Jerry', 'Sales'); console.log(jerry);

// { name: 'Jerry', role: 'Sales', id: 3 }

Closing Thoughts

To me, using closure to close off variable access from the outside really helps me see a practical use for closure. Hopefully you found this run-through of creating employee IDs as a solid real-life example of utilizing the JavaScript closure.

Thanks for reading! If you’ve enjoyed this blog post, feel free to leave a few claps and follow me!