Intro to JavaScript Classes





Learning Objectives

Students will be able to:

  • Describe the use case for classes
  • Describe encapsulation in OOP
  • Define a class
  • Instantiate a class
  • Include and use a constructor method in a class
  • Define prototype (instance) methods in a class
  • Recognize constructor functions (predecessor to classes)
  • Define static (class) methods
  • Use extends to create a subclass
  • Use super within a subclass



Lesson Setup

For this lesson, we're going to code along using a JavaScript REPL from repl.it -- you can name it "JavaScript Classes Practice".



What Are Classes?

  • In object oriented programming (OOP), we use objects to model our application's purpose.
  • Classes (as well as their predecessor, constructor functions) are used to create objects.
  • Think of classes as the blueprints used to create objects of a certain "type"...


Why Use Classes?

  • We've already been creating JS objects using object ___ notation.
  • So why do we need classes and/or constructor functions?
  • Because the number of a certain type of object needed by an application often varies at runtime; and...
  • Classes/constructors provide a convenient way to dynamically create objects as needed.


Encapsulation in OOP

  • Encapsulation is a key principle of Object Oriented Programming.
  • Encapsulation is the concept of bundling data (properties/attributes) and related behavior (methods) within an object.
  • Here comes a graphic depicting this principle...
  • Here's a code example of encapsulating data (attributes/properties) & behavior (methods):
var cohort = {
  id: 'SEIR Flex',
  students: ['Mary', 'Toni', 'Fred'],
  instructors: ['Susan', 'Phil'],
  addStudent: function(name) {
    name = name[0].toUpperCase() + name.substr(1).toLowerCase();
    this.students.push(name);
  },
  pickRandomStudent: function() {
    var rndIdx = Math.floor(Math.random() * this.students.length);
    return this.students[rndIdx];
  }
};


Review Questions

❓ What does the acronym OOP stand for?

❓ In your own words, describe why Classes exist in OOP.

❓ In your own words, describe the OOP principle known as encapsulation.




Defining Classes in JS

  • Here's a minimal class definition that's good for nothing but creating empty objects:

    class Vehicle {
      // Code to define the class's properties and methods
    }
  • Looks similar to defining a function because classes are in fact, special functions, except...

❓ What's different compared to a function?

❓ What's different about the naming convention?




Instantiating a Class

  • Here's a bit more OOP vocab for you:

    • instance: An object created by a class
    • instantiate: We instantiate a class to create an object
    • instantiation: The process of creating an object
  • In JS, we create objects using the new keyword when invoking (instantiating) the class:

    var v1 = new Vehicle();



The constructor Method

  • When a class is being instantiated, the special constructor method in the class will automatically be called:

    class Vehicle {
      constructor(vin, make) {
        this.vin = vin;
        this.make = make;
        // return is not needed 
        // because the new object is returned by default
      }
    }
    
    var plane = new Vehicle('X123Y', 'Boeing');
  • The purpose of the constructor method is to initialize the data properties of the new object being created (represented by this).
  • If there are no properties to initialize, the constructor method is optional (a hidden default constructor is called).



Practice - Add a Property

  • Modify the Vehicle class by adding an additional property named model.
  • Test it out by instantiating another object like this:

    var car = new Vehicle('A1234', 'Toyota', 'Camry');



Object Instantiation

  • When we invoke the class prefaced with the new keyword, behind the scenes:

    • JS creates a shiny new object (empty) and assigns it to the this keyword.
    • The constructor method is called with the arguments we provided when invoking the class. Remember, the constructor method is where we create/initialize properties on the new object assigned to this.
    • After the constructor is finished executing, the class automatically returns the shiny new object.
  • Although the constructor method is special because it's called automatically, there's nothing special about how it's defined, other methods are defined the same way...



Defining Methods in a Class

  • There are two types of methods that can be added to a class:

    • Prototype (instance) methods, and
    • Static (class) methods
  • Prototype methods are the most common and are available to be called by any instance of the class.What's an instance?
  • Static methods are methods that are called on the class itself and cannot be called by instances.
  • Let's add a start method to our Vehicle class:

    class Vehicle {
      // the constructor will always be called
      constructor(vin, make, model) {
        this.vin = vin;
        this.make = make;
        this.model = model;
        this.running = false;  // default to false
      }
      start() {
        this.running = true;
        console.log('running...');
      }
    }
  • Note that unlike within object literals, methods are not separated by a comma.



Practice - Defining Methods

  • Define a stop method that sets the running property to false and console.logs the message "stopped..."



Overriding Methods

  • Thanks to another OOP principle called inheritance, subclasses inherit methods from their parent classes.
  • JS is different from class-based languages like Java or Python in that its inheritance implementation is prototype-based. We won't go into prototypes during this lesson, but if you want to learn more, check out the docs here.
  • In JS, virtually every object inherits from the Object class and thus inherits it's methods, such as toString:

    car.toString() // outputs something like '[object Object]'
  • If we define a method that already exists in the object hierarchy, we "override" it. For example, we can override the Object's toString method by adding it to our class:

      // existing methods above
      
      toString() {
        return 'Vehicle (' + this.vin + ') is a ' +
          this.make + ' model ' + this.model;
      }

    Test it out.




Review Questions

You've just learned how to define a class and add prototype methods to it. This represents the majority of what you'll need to know about classes - congrats!


Review Questions:

❓ What is the JS keyword used to define a class?

❓ What is the name of the method in a class that is automatically called when we instantiate a class?

❓ What is the main purpose of this method?

❓ What character(s) separate the methods in a class definition?




Hungry for more (Further Reading):

Here is some bonus content to read through if you're hungry for more.

Constructor Functions - B.C. (before classes 😀)

  1. Before classes arrived via ES2015, we used constructor functions to do the exact same thing as classes.
  2. Because of the newness of ES2015, much of the code out there is written using constructor functions, however, most new code today is likely to be written as classes.
  3. It's important that you be able to recognize constructor functions, so let's look at how the Vehicle class can be written as a constructor function...



Constructor Functions

function Vehicle(vin, make, model) {
  this.vin = vin;
  this.make = make;
  this.model = model;
  this.running = false;  // default to false
}
Vehicle.prototype.start = function() {
  this.running = true;
  console.log('running...');
};
// other 'prototype' (instance) methods defined like above
	
var car = new Vehicle('A1234', 'Toyota', 'Camry');
  • Note that constructor functions are similar to the constructor methods in a class. Also note how instance methods are defined on the function's prototype object.
  • Invoking a class and a constructor function works identically.



Static Methods

  • Again, static methods are methods that are callable on the class itself - not on its instances.
  • Static methods are used typically to implement behavior that does not pertain to a particular instance. For example, we could design the Vehicle class so that it tracks every vehicle it creates. We could then write static methods that return how many vehicles have been created, search for vehicles by their make, etc.
  • Here's how to define a basic static method:

      static about() {
        console.log("I'm the Vehicle class!");
      }

    Yup, the only difference is the static keyword

  • As discussed, you invoke static methods on the class:

    // invoke static methods on the class
    Vehicle.about();
    
    // this will not work
    car.about();






Inheritance

  • Earlier we spoke briefly about inheritance.
  • In OOP, inheritance is when a "specialized" subclass is derived from a parent superclass, and thus inherits it's properties and methods.
  • For example, a Payment class could have CreditCard & Cash subclasses derived from it.
  • We use the extends keyword to define a subclass:

    class Plane extends Vehicle {
      constructor(vin, make, model, airline) {
        super(vin, make, model);
        this.airline = airline;
      }
      engageAutoPilot() {
        console.log('Look Mom, no hands!');
      }
    }
  • In a derived class, the super keyword represents the parent superclass and must be called before the this keyword can be used in the constructor.



Inheritance

  • Now we can create instances of Plane like this:

    var spyPlane = new Plane('secret', 'Lockheed', 'SR-71', 'USA');
  • Note how the additional arguments used to initialize subclasses are always provided after those intended for the superclass(es).
  • In complex systems, it's not uncommon to have several layers of inheritance - often referred to as an object hierarchy.



Practice - Inheritance

  • Define another subclass of the Vehicle class named Automobile with an additional property of numDoors and a honk method.
  • Test it out by instantiating it like this:

    var fastCar = new Automobile('TS123Z', 'Tesla', 'P100D', 4);
  • Hint: It's okay to copy and paste your own code (but make sure you understand what it does)



Final Notes on Classes

Unlike function declarations, class declarations are not hoisted - they must be declared before using them to create objects.




References