[Click here to view as a presentation](https://presentations.generalassemb.ly/5d66a759b3842b4a06659d1d73da25b6#/1) --- # 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):

```js 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: ```js 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: ```js 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: ```js 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: ```js 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: ```js 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](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Inheritance_and_the_prototype_chain). - In JS, virtually every object inherits from the `Object` class and thus inherits it's methods, such as `toString`: ```js 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: ```js // 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 ```js 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: ```js 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: ```js // 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?** ```js 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: ```js 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: ```js 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: ```js 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: ```js class Stack extends Array { get top() { return this[this.length - 1]; } } ``` --- ## References - [Classes on MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes) - [Prototypal Inheritance example](https://gist.github.com/jim-clark/e3fc426d73153fac6dc1)