Skip to content

Instantly share code, notes, and snippets.

@jim-clark
Last active January 30, 2020 19:38
Show Gist options
  • Select an option

  • Save jim-clark/5d66a759b3842b4a06659d1d73da25b6 to your computer and use it in GitHub Desktop.

Select an option

Save jim-clark/5d66a759b3842b4a06659d1d73da25b6 to your computer and use it in GitHub Desktop.

Click here to view as a presentation


JS 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

The Use Case of Classes


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"...


What Are Classes?



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 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...


Encapsulation in OOP



Encapsulation in OOP

  • Here's a code example of encapsulating data (attributes/properties) & behavior (methods):

const cohort = {
  id: 'SEI',
  students: ['Mary', 'Toni', 'Fred'],
  instructors: ['Susan', 'Phil'],
  addStudent: function(name) {
    name = name[0].toUpperCase() + name.substr(1).toLowerCase();
    this.students.push(name);
  },
  pickRandomStudent: function() {
    let 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:

     let v1 = new Vehicle();

    Let's use repl.it to try out the minimal Vehicle class


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
       }
     }
     
     let plane = new Vehicle('X123Y', 'Boeing');

The constructor Method


  • 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:

     let 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.


Defining Methods in a Class

  • 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]'

Overriding Methods


  • 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 about 80% there is to know about classes - congrats!

    Some questions before moving on:

  1. What is the JS keyword used to define a class?
  2. What is the name of the method in a class that is automatically called when we instantiate a class?
  3. What is the main purpose of this method?
  4. What character(s) separate the methods in a class definition?

Constructor Functions - B.C. (before classes ๐Ÿ˜€)


  • Before classes arrived via ES2015, we used constructor functions to do the exact same thing as classes.

  • 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.

  • 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
	
let 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.


Static Methods


  • Here's how to define a basic static method:

       static about() {
         alert("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();

Review Quesitons

  • Is there anything a class can implement that can't be done using constructor functions?

  • When using constructor functions, how are instance methods defined?

  • What's wrong with the following code?

     class Shape {
       constructor(x, y) {
         this.x = x;
         this.y = y;
       }
       static getPosition() {
         return [this.x, this.y];
       }
     }

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.


Inheritance



Inheritance

  • 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:

     let 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).


Inheritance

  • 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:

     let 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


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

  2. It's possible to subclass JS's built-in "classes"! For example:

    class Stack extends Array {
      get top() {
        return this[this.length - 1];
      }
    }

References

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment