JavaScript Classes: The better way to create objects

No Comments

JavaScript classes are object templates and help you create them in a cleaner way! Because of that, we will look at the different topics of classes in this post. That includes what is a class, class methods, and a core concept: inheritance!

What are JavaScript Classes?

JavaScript Classes are a different syntactic way to create objects more cleanly. Classes are only templates for an object, and you can use this template to define an infinite amount of objects with it.

Each class needs a constructor. The constructor is used to create the actual object from the class template. Every class has a constructor by default, but the default version is empty and does not let you define variables or something similar.

Input Parameters for a constructor are variables you need to initialize the object generated from the class. For example, the input parameters could be the width and height required to create the field for a game. Often you use the constructor to define class variables with the following syntax: this.varName = varName, but you can also use logic to create new class variables from the input parameters (like with the this.field):

class Field {
	constructor(width, height) {
		this.width = width;
		this.height = height;
		this.field = new Array(height).fill(0).map(() => new Array(width).fill(0));
	}
}

To create the actual object from the class, you have to create an object instance with the new keyword:

let field = new Field(2,5);
console.log(field.field);
/* console
[Array(2), Array(2), Array(2), Array(2), Array(2)]
*/

As you can see in this example, you can access the different class variables like properties of an object (because they are), and it works the same with class methods.

Now that we know the basics of JavaScript classes, we will look at how to define class methods, inheritance, and other things!

Define methods for your JavaScript classes

First, we will answer why it is called a method instead of a function. The difference is that a function can be called simply by its name. A method, on the other hand, needs to be called through the object and method names!

Now to the methods themselves. Defining a method is a pretty straightforward process. It works similar to how you would define a regular function. In case you are not familiar with standard functions yet, check out this post here.

The main difference is that you create a method in the scope of a class and that you cannot use the function keyword in front of the method definition. In the following example, we want to create a method that fills our field with random numbers between 1-9:

class Field {
	constructor(width, height) {
		this.width = width;
		this.height = height;
		this.field = new Array(height).fill(0).map(() => new Array(width).fill(0));
	}

	fillRand() {
		for (let y = 0; y < this.field.length; y++) {
      for (let x = 0; x < this.field[y].length; x++) {
          this.field[y][x] = Math.floor(Math.random() * 9) + 1;
      }
    }
	}
}

let field = new Field(2, 5);
field.fillRand();
console.log(field.field);
/* console
0: [5, 6]
1: [8, 6]
2: [1, 6]
3: [6, 1]
4: [3, 7]
*/

A thing you might notice is that we have to access our class elements with the this keyword. In the example above, we needed to do it for the field variable: this.field. Additionally, it works the same to call other methods inside of class methods because this represents the object, and as we learned above, to call a method, you need to do it based on the object containing the method.

What are static methods?

Static methods are class methods that you can call without initializing a class. They are often used for helper functions, but I have also seen them named constructors! For example, let’s create a static function that shows the differences between two fields by setting the tiles that are identical to an ‘x’ and the ones that are different to an ‘o’. Additionally, we will also create a named “constructor” that initializes the field with random numbers.

class Field {
	constructor(width, height) {
		this.width = width;
		this.height = height;
		this.field = new Array(height).fill(0).map(() => new Array(width).fill(0));
	}

	static createRand(width, height) {
		let field = new Field(width, height);
		field.fillRand();
		return field;
	}

	fillRand() {
		for (let y = 0; y < this.field.length; y++) {
      for (let x = 0; x < this.field[y].length; x++) {
          this.field[y][x] = Math.floor(Math.random() * 9) + 1;
      }
    }
	}

	// normally we would also need to check that fields have the same dimension
	static difference(a, b) {
	    let difField = new Array(a.height).fill('o').map(() => new Array(a.width).fill('o'));
	    for (let y = 0; y < a.field.length; y++) {
	        for (let x = 0; x < a.field[y].length; x++) {
	            if (a.field[y][x] === b.field[y][x])
	                difField[y][x] = 'x';
	        }
	    }
	    return difField;
	}
}

We can now first create two fields with the named constructor and then get the difference between the two fields like that:

let f1 = Field.createRand(5,5);
let f2 = Field.createRand(5,5);

let dif = Field.difference(f1, f2);
console.log(dif);
/* console
0: ['o', 'o', 'o', 'o', 'x']
1: ['o', 'o', 'x', 'o', 'o']
2: ['o', 'o', 'o', 'o', 'o']
3: ['o', 'x', 'o', 'x', 'o']
4: ['o', 'o', 'o', 'o', 'o']
*/

Get and Set in JavaScript Classes

Getter and setter are used to retrieve and set the values of a class. The benefits of get and set Are, that you can do calculations before returning or assigning a value. Additionally, you get a simpler syntax to access data, compared to a function.

One thing to keep in mind is that you cannot create a get and set named identically to the variable you want to access!

One example for a get and set could be that we want to know how many tiles our field has and that we want to set width and height by defining the number of tiles (that only works for square fields). For that, we will create a get and set for tiles:

class Field {
	constructor(width, height) {
		this.width = width;
		this.height = height;
		this.field = new Array(height).fill(0).map(() => new Array(width).fill(0));
	}

	get tiles() { return this.width * this.height };
	set tiles(v) {
		let len = Math.sqrt(v);
		if (len % 1 !== 0) {
			console.error('Root of number must be a whole number');
			return;
		}
		this.width = len;
		this.height = len;
		// update this.field size
	}
}

let f = new Field(5,5);
console.log('Tiles:', f.tiles);
f.tiles = 16;
console.log('Height:', f.height);

/* console
Tiles: 25
Height: 4
*/

Inheritance with JavaScript Classes

The last concept we will cover today is inheritance. Inheritance is a well-known concept from Object-Oriented Programming (OOP) and means that one class can inherit properties and methods from a parent class.

The cool thing about that is that you can have one general class with some general properties and methods, and the children’s classes can use and modify these functions and properties!

For example, we will rework our Field class a bit so that it only has the necessary functions and properties. After that, we will use this Field class to create a new TicTacToeField class!

class Field {
	constructor(width, height) {
		this.width = width;
		this.height = height;
		this.field = new Array(height).fill(0).map(() => new Array(width).fill(0));
	}

	setTile(x,y, val) {
		this.field[y][x] = val;
	}

	getTile(x,y) {
		return this.field[y][x];
	}
}

class TicTacToeField extends Field {
	constructor () {
		super(3,3);
	}

	setTile(x,y, val) {
		if (this.getTile(x,y) !== 0) {
			console.error(`Tile ${x}, ${y} already set`);
			return;
		}
		super.setTile(x, y, val);
	}
}

let tttf = new TicTacToeField();
console.log(tttf.field);

/* console
0: [0, 0, 0]
1: [0, 0, 0]
2: [0, 0, 0]
*/

As we can see, we have overwritten the original constructor by creating a new constructor where we call the original constructor (with super) to create a Field with the size of 3×3.

Conclusion

In this post, we learned that JavaScript classes are template objects and that you can use this template to create an infinite amount of actual objects. Inside of a class, you can define different types of elements. The regular method that can be called on an actual instance of an object, the static methods that you can call without having an actual object, and getters and setters to retrieve and update class variables.

After that, we also had a quick look at inheritance that allows you to create a new class from another class. The new class contains all class methods and variables of the original class. Additionally, you can update the functionality of the function by using the same name and calling the original method inside the new one with super.

I hope this post helped you better understand JavaScript classes and how they are used. In case you liked my post, consider subscribing to my newsletter!

Discussion (0)

Add Comment

Your email address will not be published.