Factory Function in JavaScript Explained with Examples

Robin
May 7, 2022

In a real factory, we give some inputs like raw materials and get our final products. In JavaScript, we also can create factory functions that work as a real-world factory.

Factory function can take parameters as inputs and always returns something as the finished product. In the case of a factory function, it will always return an object.

In this article, we will discuss in-depth about JavaScript factory function. What will you get from this lesson?

  • What factory function in JavaScript is.
  • When you should use the factory function.
  • How you can create a factory function in JavaScript.
  • Inheritance in JavaScript factory function.
  • Factory function vs constructor vs class
  • Many more…

What is Factory Function in JavaScript?

The factory function is a plain JavaScript function that always creates and returns a new object. This is the only purpose of creating this function. It works like a constructor function or class, but the factory function does not use new or this keyword to create a JavaScript object.

Factory functions don’t use inheritance by default like constructor functions or classes. But there is a way to enable inheritance inside a factory function.

Why should you use a function to create an object?

You can always create objects in JavaScript. It is not a very difficult task. But there are some problems with this method. That’s why factory functions are being used to resolve those issues.

Let’s see when you should use a function to create plain JavaScript objects instead of creating them manually.

When Should You Use JavaScript Factory Function?

Before using a factory function in your JavaScript code, you need to know the problems it solves or the requirements that it fulfills.

Requirement 1: If you need multiple objects with similar types of properties and methods with little difference.

For example, you want to create an object that describes a person. But you need similar types of objects for John, Max, Bob, etc.

const john = {
    name: 'John',
    age: 30,
    greet() {
        return `Hello, my name is ${this.name}`;
    }
};

const max = {
    name: 'max',
    age: 24,
    greet() {
        return `Hello, my name is ${this.name}`;
    }
};

This object has name, age properties and a greet() method. If you create objects manually, you have to do this 3 times for 3 persons. Their properties and method are the same but property values are different.

The factory function can solve this issue. With this, you can create a blueprint of your object once and create as many objects as you want with that blueprint. In this way, you can create separate objects for each person with similar characteristics but with different values.

Requirement 2: To reduce code duplication.

As you see, you don’t have to write similar kinds of objects multiple times. Using the factory function, you will create a layout of your object one time then it will create objects for you.

It is saving you time and solves the problem of code duplication.

Requirement 3: To organize your code.

By adding all the logic in one place, a factory function helps us to organize our code. When you read your code after some time or anyone else read the source code he/she will understand what this function is doing.

So, without writing many many similar types of functions all over your code, you write once in one place and use it whenever it is required.

It’s a much better approach when you want to arrange and manage your source code.

Requirement 4: If you need data privacy.

If you create an object manually in JavaScript, you can modify its properties and methods later. Many times it creates bugs in our program.

const max = {
    name: 'Max',
    age: 30,
    greet() {
        return `Hello, my name is ${this.name}`;
    },
};

max.name = 'John';

console.log(max.greet());
// Hello, my name is John

In this object, I am updating the name property. Now, when I call the greet() method on the max object, it will show John.

If you change the property values by mistake, it will give an unexpected result. But, you can solve this problem using factory functions. Then you will have your data privacy.

Requirement 5: When you want to create your objects in a simple way.

One of the main reasons developers sometimes prefer factory functions over constructor functions or classes is that it is simple.

A factory function is just a plain JavaScript function that returns an object. That’s all you need to know when you try to use it. You don’t have to use new keyword or this keyword with your factory function.

Sometimes the this keyword is hard to handle especially if you don’t know how it behaves in different situations. You can also create objects using the constructor function or class. In that case, you have to work with the this keyword.

That’s why factory functions are simple and easy to use for creating new objects.

Also Read: Self Invoking Functions in JavaScript – Why Should You Use?

How to Create Factory Function in JavaScript

You have to declare a normal JavaScript function to create a factory function. I have given you an example earlier where I want to create an object to describe a person. Let’s create a factory function so that we can create separate objects for different people.

const person = (personName, personAge) => {
    return {
        name: personName,
        age: personAge,
        greet() {
            return `Hello, my name is ${personName}`;
        },
        getAge() {
            return `I am ${personAge} years old`;
        },
        setAge(newAge) {
            personAge = newAge;
        },
        setName(newName) {
            personName = newName;
        },
    };
};

I have created a person factory function. This function accepts 2 parameters. The first one is a person’s name and the second one is a person’s age.

As a factory function always returns an object, I am returning an object with name and age properties. The object will have a few methods.

  • greet() – This method returns a string.
  • getAge() – Gives the age of a person.
  • setAge() – Accepts new age as a parameter and sets new age.
  • setName() – Accepts new name as a parameter and sets new name.

That’s it. Your factory function is ready to use. You can call this function as many times as you want to create new person objects.

const bob = person('Bob', 23)
const john = person('John', 30)
const max = person('Max', 25)

Here, I have created 3 objects bob, john, and max. All these functions are separate and independent. I can access any properties and methods.

console.log(bob.greet())
// Hello, my name is Bob

console.log(john.greet())
// Hello, my name is John

console.log(max.greet())
// Hello, my name is Max

When I call greet() method on each object, it will return messages with different names. You can see the power of factory functions.

How do factory functions provide data privacy?

In those objects, you have access to name and age properties. But if you update those properties directly, it will not have any effect on methods.

bob.name = 'Sam'
bob.age = 26

console.log(bob.greet())
// Hello, my name is Bob

console.log(bob.getAge())
// I am 23 years old

I am setting new values for name and age properties. But when I call greet() and getAge() methods, it will show the previous texts. So, these methods had no effect.

Because if you see the person factory function, methods are using function parameters personName and personAge directly. When I update the name and age properties in the object, it does not change anything in the methods.

bob.setName('Sam');
bob.setAge(26);

console.log(bob.greet())
// Hello, my name is Sam

console.log(bob.getAge())
// I am 26 years old

To get updated values from greet() and getAge() methods, you have to use setName() and setAge() methods. With these methods, you can update the values of function parameters. Therefore, greet() and getAge() methods will give updated values.

It was a very simple example I know. But in a real project, your factory function will contain many properties and methods. Your function logic will be more complex. There you will find the advantages of using factory functions.

Let’s see another example to see how you can use it with HTML DOM.

Suppose you have a div in your HTML file with an id app and you want to add HTML content dynamically using JavaScript. If you need to add dynamic HTML in many places then you can create a factory function.

const createElement = (type, content, parentId) => {
    const element = document.createElement(type);
    element.innerHTML = content;
    document.getElementById(parentId).appendChild(element);

    return {
        type,
        content,
        updateContent(newContent) {
            element.innerHTML = newContent;
        },
        addClass(newClass) {
            element.classList.add(newClass);
        },
        getClassName() {
            return element.className;
        },
    };
};

const heading = createElement('h1', 'Hello World', 'app');
const paragraph = createElement('p', 'This is a paragraph', 'app');

paragraph.updateContent('This is a new paragraph');

heading.addClass('large');
heading.addClass('main');
console.log(heading.getClassName());
// 'large main'

In this example, I have created a factory function called createElement which accepts 3 parameters.

  • type – Type of element I want to create.
  • content – Content for that HTML element.
  • parentId – ID of the parent element where I want to add the dynamic HTML element.

When I call the factory function, it will create the element using the createElement() method, add the content using innerHTML property and append the element to the parent element.

If you want to know more about dynamic HTML, I have a complete guide on creating dynamic HTML using JavaScript.

Finally, our factory function returns an object with few properties and methods. Through those methods, you can add classes or update the content.

Now you can create as many elements as you want using the same factory function. You can add more methods if you need more features.

Use Prototypal Inheritance in JavaScript Factory Function with Object.create()

The factory function does not use inheritance by default. That means every object you create using person() function will be completely separate. Even though all those objects have some common.

All the methods across those objects are the same, only properties have different values. Then why should we copy the same functions over and over again?

When we create objects, they get stored in our computer memory. As our objects have copies of the same methods, it will take more memory space. It’s definitely not an efficient memory management system.

How can you solve the issue?

You can add inheritance with the factory function in order to use the same methods across all objects that you create. In this way, methods will be stored in your computer memory just once.

All the objects you create will use a reference of the same method in the memory. Therefore, your objects created by a factory function will use less memory space.

javascript factory function without prototypal inheritance

You can see all the methods are directly inside the main object not inside the Prototype object. When we add inheritance, our methods will go inside the Prototype object. Don’t worry you can access your methods directly on the main object like bob.greet() even though they are inside the Prototype object.

You need to use Object.create() method to add inheritance. This method creates a new object using an existing object. You will find more information about this method here.

const personMethods = {
    greet() {
        return `Hello, my name is ${this.name}`;
    },
    getAge() {
        return `I am ${this.age} years old`;
    },
    setAge(newAge) {
        this.age = newAge;
    },
    setName(newName) {
        this.name = newName;
    },
};

const person = (personName, personAge) => {
    let person = Object.create(personMethods);

    person.name = personName;
    person.age = personAge;

    return person;
};

Here, I have created a personMethods object that contains all the methods. Then in the factory function, I am using Object.create() method and passing the personMethods object in it.

Note: You have to use this keyword to access properties with Object.create() method.

This method is returning a new person object. Now I can add my properties to this object and return it.

javascript factory function with prototypal inheritance

Now you can see all the methods are not directly inside the main object. Instead, they are inside the Prototype object. You are successfully using inheritance with your factory function.

Factory Function VS Constructor VS Class in JavaScript

The main function of the factory function, constructor, and class are the same. They are used to create JavaScript objects. Even though their purpose is the same, there are some differences.

  • You call factory function like a regular function. But constructor function and class need new keyword to create an object.
  • Normally the name of a factory function uses the camel case i.e. it starts with a small letter like a normal function. But by convention, the name of a constructor function or class starts with a capital letter.
  • Constructor function and class use inheritance by default. But you have to add inheritance to your factory function manually.
  • From a factory function, you have to return an object. But when you instantiate a constructor function or class with new keyword, JavaScript automatically creates and returns an object.
  • Class is an alternative way to create a constructor function. It’s just a modern syntax but the functionalities are almost the same. Because behind the scene, classes also use the constructor function.

Conclusion

In JavaScript, a factory function is just a regular function that always returns an object. In this article, I have demonstrated everything about factory functions in JavaScript, how you can create them or why you should use them.

You also have seen the differences between factory functions, constructor functions, and classes. Understanding the differences will help you to use them properly.

Thank you so much for reading. Happy coding 🙂

Related Posts