Kyle Shevlin

Software Engineer
November 05, 2021
0 strokes bestowed

What is a Factory Function?

edit

Building upon closures, I want to teach you about "factory functions", too. Factory functions often use closures, so it makes sense to learn them together. So if you don't know what a closure is or need a refresher, I encourage you to read that blog post first.

A factory function is a function that returns a new object. The key feature of a factory is that its only job is to pump out those items, just like an actual factory.

The simplest factory function returns a static object of keys and values. Ever needed to turn a small list of values into an object? Take that tuple and give it to a factory function, like so:

const createPerson = (name, twitterHandle) => ({
  name,
  twitterHandle: `@${twitterHandle}`,
})

const kyle = createPerson('Kyle', 'kyleshevlin')
console.log(kyle.twitterHandle) // '@kyleshevlin'

That's not all that interesting, but it can be a useful way to generate objects. If you had a long list of person-related tuples like this, you could use createPerson with Array.map to turn them into props for a React component.

const people = [
  ['Kyle', 'kyleshevlin'],
  ['Jane', 'janeDoe12345'],
  ['John', 'johnDoe67890'],
]

function PeopleList() {
  return (
    <ul>
      {people.map(personTuple => {
        const person = createPerson(...personTuple)

        return (
          <li key={person.name}>
            <Person {...person} />
          </li>
        )
      })}
    </ul>
  )
}

This is a great use of a factory function, but let's move on to a more interesting use case.

Replacing Classes with Factories

The place I use factories most often is when I want to return an object with methods but use closures to create private methods and values. Even better, I never have to even think about the this keyword.

When I created my data structures and algorithms course on egghead, I used factory functions to create the data structures. Let's make a createQueue factory to show you how this strategy works.

function createQueue() {
  // Create an array in closure. This is a private variable.
  const queue = []

  // This could have been a private method, if we didn't also want to expose it
  // Notice how simple this is to understand. No need for `this`
  const isEmpty = () => queue.length === 0

  return {
    enqueue(x) {
      queue.push(x)
    },
    dequeue() {
      return queue.shift()
    },
    peek() {
      if (isEmpty()) return undefined
      return queue[queue.length - 1]
    },
    get length() {
      return queue.length
    },
    isEmpty,
  }
}

const queue1 = createQueue()

What's great about this pattern is that it's compatible in every browser. Private fields and private methods for JavaScript classes are widely implemented, but not every where (and never will be).

I recently used this pattern to upgrade my shevyjs package. I was able to have truly private values and functions that I couldn't have back when I originally wrote the code. I highly recommend taking a look at the source code to see a more complex factory function in action.

Composition with Factories

There are 100s of posts out there on the difficulty of building object hierarchies with inheritance. I kind of want to skip that part and jump right to composition.

Let's imagine we're building a game with animal characters. Animals are notoriously difficult to create inheritance hierarchies for because of their diversity and literal exceptionality.

In my game, let's say I want to create Hawk, Penguin and FlyingFish factories. How can I use composition to make this possible?

There are some shared traits with these animals. Hawks and Penguins both have wings, but not FlyingFish. Penguins and FlyingFish both swim, but Hawks don't. While also Hawks and FlyingFish fly, while Penguins don't, despite their wings.

Simply put, inheritance can't help us here. Let's compose our factories:

First, we can make factories that createBirds and createFish, they will create very small objects.

const createBird = () => ({
  hasWings: true,
})

const createFish = () => ({
  hasFins: true,
})

There are more properties we could add, but we should be careful with adding too many to the base object. Next, we can create factories for objects based on what they do. Focusing on what something does, versus what it is is a great way to find these kinds of compositional pieces:

const createFlyer = () => ({
  canFly: true,
  fly(vx, vy, vz) {
    // Do something with the velocities
  },
})

const createSwimmer = () => ({
  canSwim: true,
  swim(vx, vy, vz) {
    // Do something with the velocities
  },
})

Now that we have those, we can create compositions to create our various animal factories easily:

const createHawk = () => ({
  ...createBird(),
  ...createFlyer(),
})

const createPenguin = () => ({
  ...createBird(),
  ...createSwimmer(),
})

const createFlyingFish = () => ({
  ...createFish(),
  ...createFlyer(),
  ...createSwimmer(),
})

Look how clean that is! Ahh, just fills my heart with joy. Imagine trying to do that with classes?

Summary

Factory functions are functions that return objects. We can use factory functions and closures to have private variables and private functions, only exposing what we want to our consumer through the object we return, all while avoiding the this keyword. Factories make for easy composition of values and functionality. Use them when inheritance can't solve your problems.


Finished reading?

Here are a few options for what to do next.

Like
Liked the post? Click the beard up to 50 times to show it
Share
Sharing this post on Twitter & elsewhere is a great way to help me out
Support
Was this post valuable to you? Make a donation to show it
Make a Donation
Kofi logo

Related Post:
What is a Closure?
Tags
JavaScriptComputer Science

Kyle Shevlin's face, which is mostly a beard with eyes
Kyle Shevlin is a software engineer who specializes in JavaScript, React and front end web development.

Let's talk some more about JavaScript, React, and software engineering.

I write a newsletter to share my thoughts and the projects I'm working on. I would love for you to join the conversation. You can unsubscribe at any time.

Data Structures and Algorithms Logo
Data Structures and Algorithms

Check out my courses!

Liked the post? You might like my courses, too. Click the button to view this course or go to Courses for more information.
I would like give thanks to those who have contributed fixes and updates to this blog. If you see something that needs some love, you can join them. This blog is open sourced at https://github.com/kyleshevlin/blog
alexloudenjacobwsmithbryndymentJacobMGEvanseclectic-codingjhsukgcreativeerikvorhesHaroenvmarktnoonandependabotmarcuslyonsbrentmclarkfederico-fiorinimedayzDoNormal
©2021 Kyle Shevlin. All Rights Reserved.