Classes in JavaScript provide a blueprint for the creation of objects. This means that once you define a class (including its member variables and methods), you can endlessly create new objects from it. This is useful because it allows us to reduce the amount of code we need to write when we want multiple objects that are similar to one another. This is also useful because it allows us to reuse code.

Defining a Class

Defining a class in JavaScript is simple thanks to the built-in class keyword. Let's say we run a pet store and want a JavaScript object to represent each pet. Thus, we can create a Pet class.

class Pet { } const pet = new Pet(); console.log(pet);
Pet {}

We have created a new Pet object using our defined class, assigned it to the pet variable, and printed it out.

But let's make our Pet class useful.

Constructing a Class

How you construct a class is just going to depend on what you need the class to do. In our case, since they represent a pet in a pet store, we should probably have variables for the pet's name, weight (in pounds) and price (in USD).

class Pet { constructor(name, weight, price) { = name; this.weight = weight; this.price = price; } printInfo() { return "Hi, my name is " + + ". I weigh " + this.weight + " pounds and cost $" + this.price + "."; } } const pet = new Pet("Fluffy", 20, 200); console.log(pet); console.log(pet.printInfo());
Pet { name: "Fluffy", weight: 20, price: 200 } Hi, my name is Fluffy. I weigh 20 pounds and cost $200.

In this case, we are using the constructor keyword. You can think of constructor as just a special function that asks for the data required to create a new object out of the class. Since we want every pet to have a name, weight and price, we are specifying that in our constructor.

If you noticed, we also defined a printInfo function that simply returns back a user-friendly string that describes the pet.

As mentioned before, the cool thing about classes is that you no longer need to define multiple objects but instead can use one common class. Look how easy it would be to define three different pets:

class Pet { constructor(name, weight, price) { = name; this.weight = weight; this.price = price; } printInfo() { return "Hi, my name is " + + ". I weigh " + this.weight + " pounds and cost $" + this.price + "."; } } const pet1 = new Pet("Oreo", 15, 300); console.log(pet1.printInfo()); const pet2 = new Pet("Dashy", 25, 400); console.log(pet2.printInfo()); const pet3 = new Pet("Ninja", 20, 350); console.log(pet3.printInfo());
Hi, my name is Oreo. I weigh 15 pounds and cost $300. Hi, my name is Dashy. I weigh 25 pounds and cost $400. Hi, my name is Ninja. I weigh 20 pounds and cost $350.

Class Inheritance

While our current solution works for now, it can certainly be improved upon. Our Pet class doesn't offer any distinction between a cat or a dog, which each would have additional information that doesn't apply to the other. Luckily for us, JavaScript offers class inheritance, which means we can create new classes that inherit everything from another, but adds unique information for itself.

This means that since a dog is still a pet, we can just inherit from the Pet class and add any dog-specific stuff in the Dog class. To keep things basic, let's add the ability to bark if it's a dog.

class Dog extends Pet { bark() { console.log("BARK BARK BARK"); } } const dog = new Dog("Cooper", 20, 200); console.log(dog.printInfo()); dog.bark();
Hi, my name is Cooper. I weigh 20 pounds and cost $200. BARK BARK BARK

We created a new Dog, but since it is still a pet because we inherited from the Pet class, it was able to both bark, something only dogs can do, but also return back info thanks to the printInfo function, something any pet can do.

The information we passed to the Dog class is automatically passed to the Pet class which is how printInfo worked as expected.

Function Overriding and Super Keyword

To serve as an introduction to another useful JavaScript feature, let's create a Cat class. This time, we'll have all cats have a unique feature that they each have a favorite brand of cat food, and thus will need a string to keep track of that.

class Cat extends Pet { constructor(name, weight, price, brand) { super(name, weight, price); this.brand = brand; } getFavoriteBrand() { return this.brand; } printInfo() { return "Hi, I'm a cat named " + + " and I like " + this.brand + ". I weigh " + this.weight + " pounds and cost $" + this.price + "."; } } const honey = new Cat("Honey", 15, 300, "Purina"); console.log(honey.printInfo()); console.log(honey.getFavoriteBrand());
Hi, I'm a cat named Honey and I like Purina. I weigh 15 pounds and cost $300. Purina

A couple of very interesting things is happening here. First, in the constructor for Cat, you'll notice the super keyword. This is simply manually calling the constructor of the class that Cat is inheriting from, in this case, the Pet class. The only reason this is needed is because we added a new parameter to the constructor of Cat, and that is the brand string.

Since brand is unique to cats, we assign it under the super call.

The second interesting thing that is happening here is that we defined a printInfo function inside Cat, even though there is already one inside Pet. When we do this, we are overriding the function, which means that cats will use the one defined in Cat instead of Pet, which is what we want.

Classes in JavaScript are extremely useful and versatile, as these examples have hopefully shown. You can define base classes (the Pet class) and create an endless number of classes that inherit from it (the Dog and Cat classes) which have their own unique features and functionality only private to them, which still retaining the features and functionality available to all.

You could even go further and have different breeds of dogs and cats have their own classes that inherit from the Dog and Cat class!

Private Class Fields

Relatively new to JavaScript are private class fields. A class field is a variable that is maintained inside a class. Previously, there was no way to denote that a field should only be accessible to the class itself and not for outsiders. We got around this limitation by adding an underscore in the variable name. Here's an example:

class Number { _value = 0; increment() { this._value++; } }

To other developers, the underscore would imply that the variable is only meant to be accessed internally, but nothing prevented you from doing this in another file:

const number = new Number(); console.log(number._value);

However, with the introduction of truly private class fields, we can let JavaScript enforce this for us:

class Number { #value = 0; increment() { this.#value++; } }

Now if you try doing the same thing as before and try to access the variable directly, you will get an error:

const number = new Number(); console.log(number.#value);
Uncaught SyntaxError: Private field '#value' must be declared in an enclosing class


Next Lesson »
Copyright © 2017 - 2024 All rights reserved. Made with ❤ in NY.