How to implement JS class and Inheritance

What is a JavaScript Class?

A class is a template for creating objects in JavaScript. It has properties and methods. JavaScript offers two access levels to fields and methods: public and private. The private access level is a relatively recent addition, and some browsers may not yet have the support for it.

How to create a class

In convention, the first letter of a class name is a capital letter.

Class declaration

//SYNTAX
class Class_name {
	
	constructor(){
		/*any code */
	}
	
}
//EXAMPLE 1:
class Sample_class {	
	constructor(){
		this.message = "Hello, I am from constructor"
	}
}

const sample_instance = new Sample_class();//creating an instance
console.log( sample_instance.message);//accessing properties

//EXAMPLE 2
class Sample_class {
	
	constructor( message ){
	      this.message =  message;
	}
	
}

const sample_instance = new sample_class("Hello World");
console.log( sample_instance.message )

Class declaration and hoisting

One of the important with regard to classes and hoisting is that you can not make an instance of a class before its declaration.

Const myObj = new Sample_class(); //can not hoisted. produce ReferenceError

class Sample_class {
	
	constructor(){
		/*any code */
	}
	
}

Class expression

A class in an expression can be named or anonymous.

//anonymous 
const Sample_class = class{
	
	constructor( message ){
	      this.message =  message;
	}
	
}

const instance = new Sample_class("Hello World");
console.log( instance.message )

//named classes
const Sample_class = class Message {
	
	constructor( message ){
	      this.message =  message;
	}
	
}

const instance = new Sample_class("Hello World");
console.log( instance.message );

Types of methods in class

The method is a function inside the class. 

Important methods in class

  1. Constructor
    1. Responsible for creating and initializing an object from a class template
    2. There must be only one constructor per class 
    3. A constructor of a subclass can use the super keyword to call the constructor of the superclass. ( We will discuss superclass and subclass later )
  2. Prototype methods
class Addition {	
	constructor( num1, num2 ){
	      this.num1 = num1;
			  this.num2 = num2;
	}
	//method
	add(){
		return this.num1 + this.num2
	}
	//Getter
	get total(){
		return this.add();
	}
}
const instance = new Addition( 2, 3 );
console.log( instance.total );

 A quick note on getters and setters

Getter: Get the value of an object’s property. These methods start with the get keyword

Setter: Set or edit the value of an object’s property. These methods start with the set keyword.

Learn more on getters and setters here.

Note: While JavaScript has no Protected access level, some developers suggest the use of getters and variables starting with the underscore ( _ ) operator (to restrict access). You can learn here more about this matter here as well.

  1. Generator methods
class Addition {

	constructor( ...num ){		
		    this.total = 0;
	      	    this.num_arr = num;
	}

	//Generator method
	*getTotal(){
				
			for( const num of this.num_arr ){
				this.total =  this.total + num;
				
			}
			yield this.total; 
	}


}

const instance = new Addition( 1, 2, 3,4,5 );
console.log(instance.getTotal().next().value);

Note: while I am not focusing on Generator functions in this post, I will be discussing these special functions in another post in the future. You do not need to know Generator functions to understand class or OOP concepts in JavaScript.

  1. Static methods
    1. static keywords define a static method or static property for a class
    2. These methods or properties belong to the class, and not to instances
    3. Therefore, you can not call them using an instance of a class(object). Static variables are called by only static methods.
    4. You need to use the name of the class to access static methods or static properties of a class
class Sample_class {		
	static staticMethod(){
		return 'I am from static method';
	}	
}

console.log( Sample_class.staticMethod() );

Public fields

By default, all the fields are Public. Public fields participate in prototype inheritance

Public instance fields and methods

  • Available on instances of the class
  • fields are added at construction time in the class
  • If a class has a subclass, fields are added just after super() is invoked in the subclass 
  • If you do not initialize the public instance fields, it will be set to ‘undefined’.
class Sample_class {
   publicVar = "I am public"; //public field

	publicMethod(){ //public method
		return "I am a public method";
	}
}

const sample_obj = new Sample_class();
console.log( sample_obj.publicVar );
console.log( sample_obj.publicMethod());

Public static fields and methods

  • static keyword defines static fields and methods 
  •  static fields and methods belong to the class, and not to instances of the class
  • subclasses have access to these fields via the prototype chain(prototype inheritance ).
  • When initializing static fields, this ( the keyword ) refers to the class constructor. You can also reference it by name( of the class), and use super to get the superclass constructor (if one exists).
class Sample_class {
  static baseStaticVar = 'base class static field';
  static tempStaticVar = this.baseStaticVar;//also Sample_class.baseStaticVar

  static sampleStaticMethod() { return 'This is from static method' }
}

class Sample_sub_class extends Sample_class {
  static subStaticVar = super.sampleStaticMethod()
}

console.log(Sample_class.tempStaticVar);
console.log(Sample_sub_class.subStaticVar);

Private fields

  • Accessed only within the class

Private instance fields and methods

  • Create with a # prefix the name (ex: #sample_field ). # sign is part of the name.
  • Private instance fields are added a similar to the public instance field during the construction time in the class, or If the class has a subclass, they are added at the time the super() is called in the subclass.

 JavaScript will produce syntax errors if you

  • Try to access  private fields and methods out of scope
  • Refer to fields that are not previously declared
  • Try to delete private fields

Private instance methods

  • Has the same restriction on access level as the private instance fields
  • It can be a generator, async, or async generator function,  Private getters and setters are also possible( but, not in generator, async, or async generator forms)
class Sample_class {   
	#privateVar;/*private fields must be declared before 
               initilization  */	

	constructor(){
		 this.#privateMethod();
	}

	#privateMethod(){
		console.log("I am a private method");
	}
	
	publicMethod(){
		return this.#privateVar = "This is a private field";
	}	

}
const sample_obj = new Sample_class();
console.log( sample_obj.publicMethod() );

Private static fields and methods

  • Private static fields are added to the class constructor at class evaluation time.
  • Only the class which defines the private static field can access the field. There is a restriction on private static fields:
  • One important thing to note with regard to “this” keyword and private static fields and/or methods is that if you use the “this” keyword in the base class to access private static fields or methods, it could lead to TypeErrors when using the name of the subclass.

examples:

For Feilds :

class Animal {  //base class
  static #numberOfLegs;

  static setFeatures() {
    this.#numberOfLegs = 4; 
    return this.#numberOfLegs;
  }
}

class Lion extends Animal { //subclass
	/* Any code here, not important  */
};

console.log( Lion.setFeatures() );

//when calling setFeatures() , "this" refers to the subclass, and not the base class, thus the error.
//TypeError: Cannot write private member #numberOfLegs to an object whose class did not declare it

You can avoid this TypeError if you replace “this” with the class name. Thus, the base class can be modified as:

class Animal {  

  static #numberOfLegs;

  static setFeatures() {
    Animal .#numberOfLegs = 4; 
    return Animal .#numberOfLegs;
  }
}

For methods:

class Animal { //base class	
 static #setFeatures() {
return 4
 }
static getInfo(){
	return this.#setFeatures(); //replace “this” by class name “Animal”
		
}
}

class Lion extends Animal {//subclass
	/* Any code here, not important  */
	
};

console.log( Lion.getInfo() );
//when calling setFeatures() , "this" refers to the subclass, and not the base class, thus the error.
//TypeError: Receiver must be class Animal at Function.getInfo 

Just as for fields, you can avoid this error if you use the class name instead of using the “this” keyword.

Subclass

A subclass is a child class that inherits its methods and properties from another class( base class). In addition to inherited properties and methods, it can have its own properties and methods as well.

The keyword extends makes this parent-child relationship ( relationship with the base class and subclass).

class Vehicle {
	
	constructor( owner, year, model ){
		this.year = year;
		this.model = model;		
		this.owner = owner;
	}

	getVehicleInfo(){
		console.log( "Vehicle Information");
		console.log( `${this.owner} is the owner of	the ${ this.model} manufactured in ${ this.year}`); 
	}
}


class Car extends Vehicle{
	constructor( owner, year, model ){
		super( owner, year, model );
	}

	getVehicleInfo(){
		console.log( "Car Information");
		console.log( `${this.owner} is the owner of the ${ this.model} manufactured in ${ this.year}`); 
	}
}


let item = new Car("Dinesh","2010","Toyota Corolla");
item.getVehicleInfo();

Super keyword

In class-based inheritance, the super keyword is used in the subclass to call the corresponding methods in the base class( superclass ).

You can use the super keyword in two ways

  1. super([arguments]); 
  2. super.functionOnParent([arguments]);

note: Arguments in the above syntax are optional.

As you can see in the above example, we have already used super( owner, year, model ). This is to call the constructor in the superclass.

The second way to use super is to call any corresponding method in the base class.

class Animal {	
	constructor(){
		this.animal =  "Lion\nElephant\nEgale"; 
	}

	getList(){
		return this.animal;
	}
}

class Pet extends Animal{	
	constructor(){
	  super();
		this.pet =  "Dog\nCat\nParrot"; 
	}

	getList(){		
		return this.pet ;
	}

	getAllList(){
			return  super.getList() + '\n' + this.pet ;
	}
}

let life = new Pet();
console.log( life.getAllList());

Summary

In this post, I introduced you to JavaScript classes, access levels, and JavaScript’s attempt to implement class-based inheritance. Although JavaScript is not a class-based objected-oriented language, the implementation of OOP concepts is an introduction to class-based inheritance using prototype-based inheritance.

Related Post

Leave a Reply

Your email address will not be published. Required fields are marked *