Home / Blog /
How to Use Classes in JavaScript
//

How to Use Classes in JavaScript

//
Tabnine Team /
8 minutes /
December 30, 2020

JavaScript classes were introduced in ECMAScript2015 (ES6). Classes offer an improved mean of creating object templates, replacing the previous method of using constructor functions.

Oftentimes, we are required to write code for multiple objects that have several attributes in common. For example, a set of car objects might all have the following properties: brand, model, color, etc.

Using Classes, it is possible to create a shared class for these properties. This class will serve as a template to create car instances. With this template in place, we would simply need to fill in the required properties of the class as we create each new car object instance.

Basic class example

Below is an example of creating a JavaScript class:

class Car {
    constructor(brand, model) {
        this.brand = brand;
        this.model = model;
    }
}

The code above declares a new class with the name Car.

Note: class names are conventionally defined with a capitalized letter at the beginning of the class name.

The constructor method is used to declare the class properties – e.g. brand and model. The constructor method is defined just like any other function – the parameters are wrapped in parentheses, then followed by a code block surrounded by curly brackets. These curly braces signify where the method body begins (the opening curly bracket) and ends (the closing curly bracket).

Note: There are two pairs of curly brackets in the above example. The outer pair of brackets define the class itself, while the inner pair are used to define the bounds of the constructor method.

Note: the body of a class is executed in strict mode.

Inside the constructor method’s body, the properties are assigned to this – this constructs the class itself.

Create an instance of a class

With the class defined, it’s now possible to create a new instance of a Car:

const car1 = new Car('Toyota', 'Yaris');
console.log(car1);
// Expected output: 
// Car {brand: "Toyota", model: "Yaris"}

In the example above, a new car named car1 is created using the template of class Car. This new instance has a brand and a model assigned (‘Toyota’ and ‘Yaris’, respectively)

The keyword new signifies here the creation of a new instance of the class.

The object car1 is an instance of class Car.

Note: To differentiate classes from objects, the console.log() statement above adds the class name – Car – to the output, before the object and its content are printed.

Defining a class

A JavaScript class is kind of a function. Similar to other JavaScript functions, classes can be defined using either a function expression or with a function declaration. The example above uses the declaration syntax to create a class.

Class declaration syntax

The syntax to declare a class is not complicated – simply enter the class keyword, then add the className.

If you wish to add properties to the class, define a constructor method that names the properties as its parameter list.

In the constructor, bind each property name you wish the object to have to the value of the associated parameter. In the above example, the first binding is this.brand = brand – this creates the property brand on the object. Note that it is not necessary for the property name to match the parameter name. In this example, the brand that appears after the this keyword is the key name, and the brand after the assignment operator is the expected value to be assigned when an instance is created.

Below is the general syntax for defining a class using declaration syntax:

class className {

constructor(prop1, prop2propN) {

this.propName1 = prop1

this.propName2 = prop2

this.propNameN = propN

}

}

Note: It is possible to add methods to a class. More details are available below in the Class methods section.

Note: contrary to function declarations, class declarations are not hoisted. Make sure a class is defined before it is referenced in the code.

 

Class expression syntax

Defining a class using expression syntax is nearly identical to defining a class using declaration syntax – the difference is that a variable is used as a reference to the class:

const Book = class X {
    constructor(title, author) {
        this.title = title;
        this.author = author;
    }
}

In the example above, the variable const Book is assigned the value of a classclass X. The rest of the code is identical to that of class declaration (as seen in the former examples).

Class expressions can be nameless. A nameless class will have the following first line:

const Book = class {

With nameless classes, the name of the class is omitted.

In order to create a new instance of a class defined using an expression, use the name of the referring variable in place of the class name. Remember that classes can also be nameless with this approach.

const book1 = new Book('Dr. Seuss', 'The Grinch');
console.log(book1);
// Expected output:
// X {title: "Dr. Seuss", author: "The Grinch"}

In the example above, const book1 is assigned the value of a new instance of class X by using the class expression variable name after the new keyword.

The output, despite the class having been created using the expression variable, indicates that const book1 is an instance of class X. For nameless classes, the class expression variable’s name serves as default name for the class – i.e. Book would have been printed to the console instead of X.

Class methods

So far, we made use of the constructor method to initialize class properties. A JavaScript class can also have custom methods of its own, separate from the constructor method .

Syntax

The syntax to create class methods is as follows:

class className {

methodName1() { statement(s) or code block to be executed }

methodName2() { statement(s) or code block to be executed }

methodNameN() { statement(s) or code block to be executed }

}

Class method example

Below is an example of declaring a class with a class method:

class Car {
    constructor(brand, model) {
        this.brand = brand;
        this.model = model;
    }
    drive() {
        return this.brand + ' ' + this.model + ' is driving...'
    }
}

In the example above, the definition of class Car has been expanded to include the drive() method. To add the method, we place the method name (drive) after the closing curly bracket of the constructor. We add parenthesis to the method name to indicate the argument list (empty in this example). Finally, we add a block of code surrounded by curly brackets – this code will be executed whenever the method is invoked. In the example above, a return statement will be called every time drive() is invoked.

const car1 = new Car('Toyota', 'Yaris');
console.log(car1.drive());
// Expected output:
// Toyota Yaris is driving...

Once an instance of the Car class has been created, the method can be invoked. The method is invoked through the instance, using the pattern classInstance.methodName(). In the example above, the drive() method prints the car’s brand and model, along with “is driving…”, to the console.

Static methods

In addition to the methods defined above, classes in JavaScript can also define static methods. These methods are not available on the instances of the class created, but rather only on the class itself. They are mainly used for utility functions, or shared functionality common to all instances of a class.

To create static methods, simply place the static keyword in front of the method’s name as seen below:

class Car {
    constructor(brand, model) {
        this.brand = brand;
        this.model = model;
    }
    drive() {
        return this.brand + ' ' + this.model + ' is driving...'
    }
    static stop() {
        return 'Car stopped'
    }
}

In the above example, the drive() method is a regular method available on an instance of the class, and the stop() method is a static method available on the class itself. You can now invoke the class method by directly referencing the class name, as seen below:

console.log(Car.stop());
// Expected output: Car stopped

Trying to invoke the stop() method from a class instance – e.g. car1 – will lead to a Type Error:

console.log(car1.stop());
// Expected output:
Uncaught TypeError: car1.stop is not a function

Note: It is possible to send a class instance to a static method as a parameter.

Getters & Setters

Classes can include getters and setters, which are used to manipulate object properties.

A getter is used to retrieve a certain value from the object. This can be a property, or a dynamically-computed value.

A setter is used to set a property’s value.

Getter / Setter example

Below is an example of using getters and setters in a class definition:

class Car {
    constructor(brand, model) {
        this.brand = brand;
        this.model = model;
    }
    drive() {
        return this.brand + ' ' + this.model + ' is driving...'
    }
    static stop(car) {
        return `${car} stoped`
    }
    set type(x) {
        this.model = x;
    }
    get type() {
        return this.model;
    }
}

In the above example, The methods set type(x) and get type () were added to class Car.

The method set type() receives one parameter, which then updates the car’s model property.

Note: the name of the set / get methods cannot be the same as any properties of the class. In the example above, it was not possible to define get model or set model methods because model is a property of class Car.

Setters / getters are not activated like other methods. When a value is assigned to the name used, the method serves as a setter. When no value is assigned, though, the same method serves as a getter. The following example demonstrates how this works:

car1.type = 'Prius';		// type serves as a setter
console.log(car1.type);		// type serves as a getter
// Expected output: Prius

In the above example, the first line references the type getter/setter using an assignment operator (=). This means that the first line uses type as a setter, setting car1’s model property to be ‘Prius’ instead of ‘Yaris’. The second line, by comparison, uses the type getter/setter without an assignment operator, passing it as an argument to console.log(). This second line uses type as a getter. The getter returns the value of the model property, which is now set to Prius.

Class extensions

Class extensions create a hierarchy of class definitions. These extensions are useful when dividing class definitions into multiple related groups – class extensions inherit the methods and properties of the parent class, and can also include their own in their definition.

For example, electric cars are cars which use electricity to power their engine instead of fuel. Most likely, many properties of electric cars will be the same as their car equivalents, with only some needing to be added or changed. Instead of creating an entire new class with all of the properties in Car being duplicated, we use class extensions to create a new class. This new class uses an inheritance mechanism to include all of the properties of the parent class in the newly-derived class definition.

Class inheritance example

The following example demonstrates how properties are inherited from a parent class (the base class) to a child class (the extended class):

class EvCar extends Car {
    constructor(brand, model, requireGas) {
        super(brand, model)
        this.requireGas = false
    }
}

Let’s review the code above step by step:

The first line declares a new class – class EvCar – which extends class Car. The extend keyword creates the new class as a child of the parent class, allowing it to inherit properties from the parent class.

The second line applies the constructor method , which has three parameters. The first two parameters are similar to those of the parent class (Car), while the third parameter is a new parameter.

The third line uses the super keyword , which calls the parent class’ constructor. In essence this is a function call to the parent class’ constructor method, setting the values of brand and model using the parent class’ constructor definition.

The third parameter is assigned a default value – false.

const car2 = new EvCar('VW', 'e-Up');
console.log(car2);
// Expected output: 
// EvCar {brand: "VW", model: "e-Up", requireGas: false}

In the example above, the variable const car2 points to a new EvCar instance. The code passes in two arguments to the EvCar constructor, one for the brand and one for the model. Printing car2 to the console reveals that it is an instance of EvCar.

Method inheritance

The methods of class, along with its getters and setters, are automatically inherited when the class is extended.

console.log(car2.type);
// Expected output: e-Up
console.log(car2.drive());
// Expected output: VW e-Up is driving...

In the above example, the get type() method of class Car is applied to the instance of the child class EvCar, printing the model to the console as expected. The drive() method of class Car is also available to instances of class EvCar.

 

Related Articles

JavaScript – Objects Explained

JavaScript – How to Use functions

JavaScript – How to Use switch Statements