Classes in JavaScript

An introduction to Classes and how to use them in JavaScript

What is a Class in programming? Often in programming we think of Classes as BLUEPRINTS for constructing an object. Classes are one of the features introduced in the ES6 additions to JavaScript. You may even hear developers refer to classes as "syntactic sugar" over constructor functions. We talked about objects and constructor functions in previous articles. Let's review an important concept in JavaScript about constructing objects.

Constructor Function:

function User (username, email, password) {
    this.username = username,
    this.email = email,
    this.password = password
}

// create an object instance
const user = new User("kiresmith", "ksmith@company.net", "iLikeTacos");

Classes Are Functions

A JavaScript class is a type of function. Classes are declared with the class keyword followed by the name of the class capitalized, similar to how we name constructor functions.

Defining a Class: (Syntax)

class User {
   constructor(username, email, password) {
      this.username = username;
      this.email = email;
      this.password = password;
   }
}

The properties are assigned to the newly created object in the constructor function. You may have noticed that we have a function named constructor( ). This is another JavaScript keyword that we must use specifically. The constructor function within our class binds the arguments passed in to the properties defined (prefixed with this.propertyName) to the object instance when it is created.

Instantiating a “new” Object:

The constructor method is run when a new object instance is created, this is why we need to use the "new" keyword when creating each object instance.

// instantiate a new User object instance using our User Class definition
let user = new User("pluto", "woof@company.net", "mickeymouse");

console.log(user); 
// output -> { username: "pluto", email: "woof@company.net", password: "mickeymouse" }

Class Methods:

Inside of classes we refer to functions as methods. Methods are functions, but they are functions that are associated with an object.

Wait ... are they the same? Are they different?

Functions vs. Methods:

  • A function is a set of instructions that can be performed on data or variables and the result returned.
  • A method, similar to a function, is a set of instructions that perform a task. The difference is that a method is associated with an object, while a function is not.
class User {
   constructor(username, email, password) { 
      this.username = username;
      this.email = email;
      this.password = password;
   }

   // method definitions
   greet() {
      console.log("Welcome " + this.username + "!");
   }

   login(email, password) {
      // code logic to log a user in
      if(email == this.email && password == this.password) {
          return "User Authorized";
       } else {
          return "User NOT Authorized";
       }
   }
}

// Create a new User instance object
let userA = new User("Pluto", "pluto@company.net", "woof");
let userB = new User("Mickey", "mickey@company.net", "mouse");

// Call methods on our instance object
userA.greet();          // output --> "Welcome Pluto!"
userB.greet();          // output -> "Welcome Mickey!"
userA.login("pluto@company.net", "wooooof");      // output -> "User NOT Authorized"

Static Variables and Methods:

Static variables and static methods are shared amongst all instance objects of a Class. Class properties are created by way of the constructor function, as such each instance of an object has its own specific values associated. A static variable differs in that every object has the same static property value.

class User {
   // static properties
   static count = 0;

   // static method definitions
   static getCount() { 
       return User.count;
   }
}

When you want or need to access a static property value we need to call it on the Class followed by a dot . and the static property name.

console.log("Count: " + User.count)         // output -> Count: 1

Extending a Class: Inheritance

We also have the ability to extend a class using inheritance. Extending a class allows it to inherit all the methods from the parent class. We will talk more about inheritance in a future article but let's start by taking a look at how we do this in JavaScript with the extends keyword.

// Parent Class
class User {
   constructor(username, email, password) {
      this.username = username;
      this.email = email;
      this.password = password;
   }

   greet() {
      console.log("Welcome " + this.username + "!");
   }
}

// Extending the Parent Class (Inheriting from the Parent Class)
class AdminUser extends User {
    constructor(username, email, password, isAdmin) {
       super(username, email, password);
       this.isAdmin = isAdmin;
    } 

   // AdminUser specific methods
   addUser(username, email, password, department, office) {
         // code to add a new User
   }
}

When calling super() within our constructor we get access to all the properties and methods of the parent class. But what is happening when the JavaScript interpreter runs the super(...args) method? This is a simplified explanation, there is actually more happening under the hood, but since we are just starting to learn here, let's start with what is going to help us understand but not completely confuse us. When the super() method is invoked what is happening behind the scenes for us is that the super() method is calling the constructor function of the Parent Class that we are extending. This is also a reason why if we are inheriting object properties from our Parent Class we include them in the super(username, email, password) definition within our Child Classes construction function.

Method Overriding:

We also have the ability to override a method that we inherit from the Parent Class. To override a method, we give it the same name and parameters, if any, as the method defined in the parent class.

// Parent Class
class User {
   constructor(username, email, password) {
      this.username = username;
      this.email = email;
      this.password = password;
   }

   login(email, password) {
      if(email == this.email && password == this.password) {
          return "User Authorized";
       } else {
          return "User NOT Authorized";
       }
   }
}

// Extending the Parent Class (Inheriting from the Parent Class)
class AdminUser extends User {
    constructor(username, email, password, isAdmin) {
       super(username, email, password);
       this.isAdmin = isAdmin;
    } 

   // override login method
   login(email, password) {
      // code logic to log a user in
      if(email == this.email && password == this.password && this.isAdmin == true) {
          return "Admin User Authorized";
       } else {
          return "User NOT Authorized Admin";
       }
   }
}

What happens when a regular (non admin) User logs in versus what happens when a AdminUser logs in? When we override a method that we inherited from a parent class we use the same name defined in the parent class as well as the parameters defined, if any, and we add new logic that we want our Child Class objects to run when an overridden method is called.

let regularUser = new User("Darkwing Duck", "darkwing@duck.net", "imbatduck");
let adminUser = new AdminUser("Scrooge McDuck", "money@duck.net", "richyrich");

regularUser.login("darkwing@duck.net", "imbatduck");     // output -> "User Authorized"
adminUser.login("money@duck.net", "richyrich");              // output -> "Admin User Authorized"

There is much more depth on how we use and construct objects and classes in JavaScript. We will get there but you have to start some fundamental building blocks and hopefully this article helped you get a little more understanding on our continuing development journey.

Hopefully this article on Classes in JavaScript was useful to you. Thanks for reading, until next time!