DEV Community

Cover image for Factory Functions and Constructor Functions in JavaScript
odi pearl
odi pearl

Posted on • Edited on

Factory Functions and Constructor Functions in JavaScript

A factory function is a function that creates objects and returns them. But why do we need a function to create objects, cant we just do this?

const object = { ... }
Enter fullscreen mode Exit fullscreen mode

Thats a way to create an object for sure but that has a small issue with it especially if we are making more than one object and especially if all of those objects had a lot of things in common with just little differences.

So imagine we wanted to create objects that would represent all your classmates for example, and we wanted to have a reply function that announces who that classmate is. It might look something like this:

const kali = {
    name: 'kali',
    reply() {
        return `${this.name} is present`
    }
}

const pearl = {
    name: 'pearl',
    reply() {
        return `${this.name} is present`
    }
}

kali.reply()  // 'kali is present'
pearl.reply() // 'pearl is present'
Enter fullscreen mode Exit fullscreen mode

So you can see that say we had 100 classmates we might need to create a new object for each one of them. You do not want to write your logic more than once, even twice. Thats really bad. Someone once said "I could just use find and replace in VS Code". Really?

Okay so lets look at another problem with this code:

pearl.reply() // 'pearl is present'
pearl.name = 'sam'
pearl.reply() // 'sam is present'
Enter fullscreen mode Exit fullscreen mode

You can see that later on in my code I renamed pearl to 'sam' and it just overwrote it. In my opinion this is similar to the problem we had with var where you could change the value of a variable later in the code and this is one of the main sources of bugs in a codebase.

Now lets do this using a factory function

So think of a factory function as an actual factory, lets say a phone factory. Stuff goes in as raw materials (parameters), the factory does a bunch of things to them and then the phone comes out (the object). Factory functions are not that different.

Let me show you what I mean:

function classFactory(name) {
    return {
        reply() {
            return `${name} is present`
        }
    }
}

const kali = classFactory('Kali')
const percy = classFactory('Percy')

kali.reply()  // 'Kali is present'
percy.reply() // 'Percy is present'
Enter fullscreen mode Exit fullscreen mode

So now instead of creating the full object every single time, we just create a function and call it with the name of the person. And with this you cant even accidentally override the name because its locked inside the function.

So like we said in the beginning this is good for objects that have a lot in common, like in this case the reply, with just a little difference which in this case is the name we are calling. So its best we isolate all the common logic into one place and only allow the value that is dynamic to change.

Now lets look into constructor functions

A constructor function is also a function that creates objects for us, but with a constructor function we introduce the this keyword and the new keyword. By convention constructor functions start with a capital letter.

Lets look at this example:

function Classmate(name) {
    this.name = name
    this.reply = function() {
        return `${this.name} is present`
    }
}

const kali = new Classmate('Kali')
console.log(kali)
// Classmate { name: 'Kali', reply: f }

kali.reply() // 'Kali is present'
Enter fullscreen mode Exit fullscreen mode

We can see that it gives us back an object. Now notice that we are not using a return statement in the Classmate function and ill explain why.

So when we put new in front of a function call, JS automatically does two things for us. First it creates an object inside the function and calls it this, then it returns that this object back to where it was called. We wont see any of this take place but thats what happens behind the scenes. So it looks something like this:

function Classmate(name) {
    const this = {}         // created automatically
    this.name = name
    this.reply = function() {
        return `${this.name} is present`
    }
    return this             // returned automatically
}
Enter fullscreen mode Exit fullscreen mode

So now we can use the function to create objects without doing any of those repetitive steps. In real world situations the function will be a lot more complex than this.

Lets now make this more interesting so we can scale it — instead of writing each name one after the other we can just use an array:

const names = ['Kali', 'Andrew', 'Pearl', 'Percy']

const classmates = names.map(name => new Classmate(name))

classmates.forEach(c => console.log(c.reply()))
// 'Kali is present'
// 'Andrew is present'
// 'Pearl is present'
// 'Percy is present'
Enter fullscreen mode Exit fullscreen mode

We can see that we have made it even better and less repetitive, and this is just a shallow way to show the power of reusability.

Conclusion

So we looked at why creating objects one by one is a bad idea especially when they all look the same with just little differences. We saw how a factory function fixes that by letting you pass in only what changes and handling all the repeated logic in one place. Then we looked at constructor functions which do the same job but with new and this handling things behind the scenes for you. And finally we saw how you can pair either of them with an array to scale things up without writing the same thing over and over. The whole point is simple, write your logic once, reuse it everywhere.

Top comments (0)