An introduction to constructor functions

Overview

If you're new to JavaScript and have experience in a class-based object-oriented language, you might be wondering how you can create custom objects in JavaScript. In this post, you'll learn about constructor functions, which is one method of creating user-defined objects and function similarly to classes.

To fully understand this post, you should be familiar with JavaScript and have a basic understanding of JavaScript functions and objects.

The Car object

We'll be creating a constructor function to create Car objects. Here's how an object representing a 1999 Honda Accord might look like if we defined it using object literal syntax:

const accord = {
    make: 'Honda',
    model: 'Accord',
    bodyStyle: 'sedan',
    year: '1999',
};

console.log(
    `This ${accord.make} ${accord.model} ${accord.bodyStyle} was built in ${accord.year}.`
);

// Output: "This Honda Accord sedan was built in 1999."

If we just have some one-off car object that we need to make, this would be fine. But if you need to represent a lot of different cars, it would be nice to have a way to reuse common Car properties. This is where constructor functions come in.

Creating a constructor function

A constructor function is a function that creates a new object. Creating it is similar to creating any other function in JavaScript: it can have parameters, has a name, and is declared with the function keyword. We'll create a Car constructor function that takes in the make, model, bodyStyle, and year as arguments; here is what it looks like without its body implemented:

function Car(make, model, bodyStyle, year) {
    // TODO: Set properties
}

Note: By convention, constructor functions start with a capital letter (Pascal case) so that we properly initialize them and don't confuse them with non-constructor functions.

We can set the properties of our custom object by defining them on this, which will refer to the new object that is created:

function Car(make, model, bodyStyle, year) {
    this.make = make;
    this.model = model;
    this.bodyStyle = bodyStyle;
    this.year = year;
}

This almost looks like typical class syntax from an object-oriented language, but it's a function––and we're not returning anything. So what's happening here? To understand this, let's look at how we create an instance of our Car.

Creating an instance of Car with new

Creating an instance of Car is like calling a normal JavaScript function, but we also use the new keyword before the function name. You may be familiar with this syntax if you've used a class-based language such as Java or C#. Here's how we create an instance of the same accord defined earlier but with our new constructor function:

const accord = new Car('Honda', 'Accord', 'sedan', '1999');

Now that we know how to create a Car object, let's clarify how this is working. When we call a constructor function with new, JavaScript will:

  • Create a new, empty object
  • Call the constructor function with the value of this pointing to the new object
    • Thus, the properties specified on this in the function will be set on the new object
  • Return the new object

Under the hood, this process looks similar to this:

// Create a new object
const obj = {};

// Call Car, with the value of `this` being the new `obj` object
Car.apply(obj, ['Honda', 'Accord', 'sedan', '1999']);

// Return obj

Adding a method

Just having a property for the car's model year probably isn't that interesting. Let's create a method that will return a car's age. To do this, we'll add a getAge property on Car's prototype property. It will be a function that returns the age as a number:

Car.prototype.getAge = function () {
    return new Date().getFullYear() - this.year;
};

Simply put, properties on an constructor function's prototype property are inherited by every instance. But why can't we just define getAge as a property of Car? Here's what that looks like:

function Car(make, model, bodyStyle, year) {
    this.make = make;
    this.model = model;
    this.bodyStyle = bodyStyle;
    this.year = year;

    this.getAge = function () {
        return new Date().getFullYear() - this.year;
    };
}

This is valid and will give you the same behavior. However, this creates a getAge function every time a new Car is created. By placing the property onto Car's prototype, we can share one reference to the function across all instances. (This is not very useful in our example, but is important to be aware of.)

Conclusion

Constructor functions in JavaScript allow us to create custom objects. They are declared like other functions, but set properties on this and are instantiated with the new keyword. We capitalize the function name so that we know it's a constructor function.

Now that you've learned about constructor functions, you might be interested in learning about how inheritance and prototypes work. I will be writing a blog post on this soon and will update this post once it is published. In the meantime, you can read Inheritance and the prototype chain from MDN.

Let's connect

Come connect with me on LinkedIn, Twitter, and GitHub!

If you found this post helpful, please consider supporting my work financially:

☕️Buy me a coffee!

References


Subscribe for the latest news

Sign up for my mailing list to get the latest blog posts and content from me. Unsubscribe anytime.