JavaScript Classes

With the introduction of the ES2015 (ES6) standard, JavaScript has a new way of defining objects – using classes. A class represents a description of an object, its state, and its behavior, and an object is a particular instance or instance of a class.

class definition

The class keyword is used to define a class :

class Person{ }

After the word class comes the name of the class (in this case the class is called Person), and then the body of the class is defined in curly braces.

This is the most common way to define a class. But there are other ways too. So, you can also define an anonymous class and assign it to a variable or constant:

const Person = class{}

In principle, we can also create a non-anonymous class and assign it to a variable or constant:

const User = class Person{}

Creating objects

A class is a generic representation of some entity or object. The specific embodiment of this representation, class is an object. And after the class is defined, we can create objects of the class using the constructor:

 
class Person{}
 
const tom = new Person();
const bob = new Person();

To create an object using a constructor, the new keyword is first set. Then the constructor is actually called – in fact, a function call by the class name. By default, classes have one parameterless constructor. Therefore, in this case, when the constructor is called, no arguments are passed to it.

It is worth noting that, unlike functions, in order to use a class, it must first be defined. For example, in the following code, we will get an error because we are trying to use the class before it is defined:

const tom = new Person(); // Uncaught ReferenceError: Cannot access ‘Person’ before initialization

class Person{}

If a class definition is assigned to a variable or constant, then we can use the name of that variable/constant to create class objects:

const User = class Person{}
const tom = new User();
console.log(tom);

Above in the code, even though we are using the call new User(), in reality the object being created will represent the Person class.

An example of creating an anonymous class object:

const Person = class{}
const tom = new Person();
console.log(tom);

Fields and class properties

Fields and properties are used to store the data or state of an object in a class.

So, the Person class was defined above, which represented a person. A person has distinguishing features, such as name and age. Let’s define fields in the Person class to store this data:

class Person{
    name;
    age;
}
const tom = new Person();
tom.name = "Tom";
tom.age = 37;
console.log(tom.name);  // Tom
console.log(tom.age);   // 37

The field definition actually just represents its name:

name;
age;

So, there is a field defined here name to store the person’s name, and a field to store the person’s age.

After creating the class object, we can access these fields. To do this, the field name is indicated after the object name separated by a dot:

tom.name = "Tom"; // set field value
console.log(tom.name); // get value properties

In the example above, class fields can also be called properties. Essentially, properties represent externally accessible or public fields of a class. Next, we will analyze in detail when the fields are non-public, that is, inaccessible from the outside. But for now, it’s worth understanding that properties and public fields are one and the same. And in the example above, the name and age fields can also be called properties.

If necessary, we can assign some initial values ​​to the fields:

class Person{
    name = "Unknown";
    age= 18;
}
const tom = new Person();
console.log(tom.name);  // Unknown
tom.name = "Tom";
console.log(tom.name);  // Tom

Class Behavior and Methods

In addition to storing data that defines the state of an object, a class can have methods that define the object’s behavior – the actions that the object performs. For example, let’s define a couple of methods in the Person class:

class Person{
    name;
    age;
    move(place){
        console.log(`Go to ${place}`);
    }
    eat(){
        console.log("Eat apples");
    }
}
const tom = new Person();
tom.move("Hospital");   // Go to Hospital
tom.move("Cinema");     // Go to Cinema
tom.eat();              // Eat apples

Here, a method is defined move()that represents the conditional movement of a person. As a parameter, the method takes the place to which the person is going. The second method – eat()- represents the conditional process of nutrition.

Accessing fields and methods within a class. word this

What if we want to refer to class fields or other class methods in class methods? In this case, the name of the field/property or method is preceded by the keyword this, which in this case points to the current object.

For example, let’s define a method that displays information about an object:

class Person{
    name;
    age;
    print(){
        console.log(`Name: ${this.name}  Age: ${this.age}`);
    }
}
const tom = new Person();
tom.name = "Tom";
tom.age = 37;
tom.print();    // Name: Tom  Age: 37
 
const bob = new Person();
bob.name = "Bob";
bob.age = 41;
bob.print();    // Name: Bob  Age: 41

Constructor definition

The constructor is used to create a class object:

const bob = new Person();

Calling the default constructor found in classes is actually calling a method that has the same name as the class and returns an object of that class.

But we can also define our own constructors in classes:

class Person{
        name;
        age;
        constructor(){
            console.log("Constructor call");
        }
        print(){
            console.log(`Name: ${this.name} Age: ${this.age}`);
        }
    }
    const volume = new Person(); // Call constructor
    const bob = new Person(); // Call constructor
    

A constructor is defined with a method named constructor. In fact, this is a regular method that can take parameters. In this case, the constructor simply prints some message to the console. Accordingly, when executing the line

const tom = new Person();

We will see a corresponding message in the browser console.

Typically, the purpose of a constructor is to initialize an object with some initial data:

class Person{
    name;
    age;
    constructor(personName, personAge){
        this.name = personName;
        this.age = personAge;
    }
    print(){
        console.log(`Name: ${this.name}  Age: ${this.age}`);
    }
}
const tom = new Person("Tom", 37);
tom.print();    // Name: Tom  Age: 37
const bob = new Person("Bob", 41); 
bob.print()     // Name: Bob  Age: 41

Here the constructor takes two parameters and passes their values ​​to the class fields. Accordingly, when creating an object, we can pass the appropriate values ​​​​for these parameters to the constructor:

const tom = new Person("Tom", 37);

It is worth noting that in the example above, the definitions of the class fields are redundant. Referring to the fields via in the constructor this will actually be similar to their definition, and in this case we can remove the definition of the fields:

class Person{
 
    constructor(personName, personAge){
        this.name = personName;
        this.age = personAge;
    }
    print(){
        console.log(`Name: ${this.name}  Age: ${this.age}`);
    }
}
const tom = new Person("Tom", 37);
tom.print();    // Name: Tom  Age: 37
const bob = new Person("Bob", 41); 
bob.print()     // Name: Bob  Age: 41