Skip to content
back to top
Just the code, please

Shailesh Codes

MICROBLOG

Using closures to create JavaScript factories

By Shailesh Vasandani — Last updated on December 27, 2020 — Reading time: 2 min

microblog javascript testing
More from MICROBLOG

How to store data with IndexedDB

It's well supported, allows you to store large files, and isn't even that bad to work with.

Making cool toggleable CSS states

A new super-short, super-sweet blog series.

Hi everyone! In today's Microblog post, we'll be looking at JavaScript closures and how you can use them to make factories.

First, though — why learn about this technique? Well, even though many people dive straight into frameworks like React and Angular, it's always good to understand the fundamental vanilla JavaScript underlying those frameworks. As a result, you'll be able to do more both with and without the frameworks supporting you. Now, onto closures:

What are closures?

Good question. At their core, closures are simply an enclosed scope inside a function. They allow an inner function to access the variables in an outer function. A super simple example would look something like this:

        
      const addTo = (numberOne) => {
        return (numberTwo) => {
          return numberOne + numberTwo;
        }
      }

      const addToFive = addTo(5);
      const addToTen = addTo(10);

      addtoFive(3); // => 8
      addToTen(3); // => 13

When the addTo function is called with a parameter, it returns another function that has access to the numberOne variable; this returned function is the closure. Both addToFive and addToTen each have their own unique scope, where the variable numberOne equals 5 and 10 respectively. As a result, when calling those functions with 3 as a parameter, they give the expected results of 8 and 13. Now, onto factories:

What are factories?

Factories are generally used in testing to create objects without creating the full object declaration inline. A simple example might look this:

        
      /* User {
        {string} firstName
        {string} lastName
        {number} age
      }
      const createUser = (userObj) => {
        // create mock user
        let user = {
          firstName: "John",
          lastName: "Doe",
          age: 21
        };

        Object.keys(user).forEach((userKey) => {

        });

        return user;
      }

This allows us to scope our testing to be more relevant to the tests we perform.

        
      // WITHOUT FACTORY
      const returnsFalseForMinors = () => {
        // irrelevant data in test
        let user = { firstName: "John", lastName: "Doe", age: 17 });

        console.assert(functionToTest(user), false);
      }

      // WITH FACTORY
      const returnsFalseForMinors = () => {
        let user = createUser({ age: 17 });

        console.assert(functionToTest(user), false);
      }

Factories and closures, together?

When we use factories together with closures, we're able to dynamically generate useful functions that don't have to take too many parameters. Here's an example from the codebase for my photography page, where I needed to add and remove different classes for large amounts of objects:

        
      // closure and factories, working together
      const removeAndAdd = (remove, add) => {
        return (el) => { 
          el.classList.remove(remove);
          el.classList.add(add);
        }
      }

      // methods generated by the factory for use later
      const leftToCenter = removeAndAdd("left", "center");
      const centerToRight = removeAndAdd("center", "right");
      const rightToCenter = removeAndAdd("right", "center");
      const centerToLeft = removeAndAdd("center", "left");

      // ...

      const movePrev = () => {
        if (currentIndex <= 0) return;
        else {
          centerToRight(images[currentIndex]);
          leftToCenter(images[--currentIndex]); // decrement inline
          labelText.innerHTML = (currentIndex + 1) + "/" + numImages;
          labelTitle.innerHTML = altText[currentIndex];
        }
      }

      const moveNext = () => {
        if (currentIndex + 1 >= numImages) return;
        else {
          centerToLeft(images[currentIndex]);
          rightToCenter(images[++currentIndex]); // increment inline
          labelText.innerHTML = (currentIndex + 1) + "/" + numImages;
          labelTitle.innerHTML = altText[currentIndex];
        }
      }

As you can see, by using a closure as a function factory, I was able to avoid repeating calls to each element's classList, making my code more readable and semantic in the process.

I hope this short post gives you an idea of the power of closures in JavaScript, and I'm hoping to make a longer post further down the line detailing the most powerful ways these can be used. Make sure to follow me to be notified when that post drops.

If you found this post useful, please consider buying me a coffee. Until next time!

Subscribe to my mailing list!

Hey there! Subscribe to my mailing list to get monthly updates on my most useful posts, and any special announcements I have. No spam, ever — promise. All fields are required.
Recommended for you

Low risk, high reward

An intro to site reliability engineering

CPR for your app: some tricks to try

What to do when your app just isn't running.

How to store data with IndexedDB

It's well supported, allows you to store large files, and isn't even that bad to work with.

Real-life examples of JavaScript's filter function

The third and final part of a series on JavaScript's array functions.

Comments

Write a comment!

All comments are moderated, and will only be published if they're constructive and add to the discussion. Thanks in advance! All fields are required.

copy