# 0.4.4: Classes

## Learning Objectives

1. Understand the motivation behind JavaScript classes and object-oriented programming (OOP)
2. Understand how to use JavaScript class syntax to create and use classes
3. Understand how class inheritance works, how to use `super` to call parent class constructor

## Introduction

The following is an example of a JavaScript class that represents cars. For simplicity, these cars only travel 1 unit of distance per trip.

```javascript
class Car {
  // Define class properties in a constructor method
  constructor(colour) {
    this.colour = color;
    this.odometer = 0;
  }

  // Define class methods within the class block
  drive() {
    this.odometer += 1;
  }
}

// Create new "instances" of classes with the "new" keyword
const whiteCar = new Car("white");
const blackCar = new Car("black");

// Call class methods on instances of the class
whiteCar.drive();
blackCar.drive();
blackCar.drive();

// Retrieve class properties as we would with JS Objects
console.log(whiteCar.odometer); // 1
console.log(blackCar.odometer); // 2
```

JavaScript classes are templates for entities we may wish to manipulate as a unit in our apps. Classes are part of a broader computer science concept called object-oriented programming, also known as OOP. Classes are optional in JavaScript but mandatory in languages such as Java.

## Without classes

Without classes, we might store data in JavaScript Objects and manipulate them with helper functions.

```javascript
const whiteCar = {
  colour: "white",
  odometer: 0,
};

const blackCar = {
  colour: "black",
  odometer: 0,
};

const drive = (car) => {
  car.odometer += 1;
};
```

To reduce redundancy in object creation, we could write a helper function like `createCar` to generate our objects.

```javascript
const createCar = (colour) => {
  return {
    colour: colour,
    odometer: 0,
  };
};

const drive = (car) => {
  car.odometer += 1;
};

const whiteCar = createCar("white");
const blackCar = createCar("black");
```

## With classes

JavaScript classes encapsulate the entity properties (`colour` and `odometer` above), entity creation method (`createCar` above) and any entity helper methods (`drive` above) within a single unit, i.e. class. This helps us organise our code by thinking of a `Car` as a single entity, instead of an entity spread across disparate objects and helper functions.

```javascript
class Car {
  // Define class properties in a constructor method
  constructor(colour) {
    this.colour = color;
    this.odometer = 0;
  }

  // Define class methods within the class block
  drive() {
    this.odometer += 1;
  }
}

// Create new "instances" of classes with the "new" keyword
const whiteCar = new Car("white");
const blackCar = new Car("black");
```

We can represent many common app entities as classes, for example users.

```javascript
class User {
  constructor(name, email, password) {
    this.name = name;
    this.email = email;
    // Always only store hashed passwords to mitigate problems if data stolen
    this.passwordHash = hash(password);
  }

  changePassword(newPassword) {
    this.passwordHash = hash(newPassword);
  }
}

const joe = new User("Joe", "joe@joe.com", "joerox");
const amy = new User("Amy", "amy@amy.com", "amyrox");
```

Naming convention: Classes are typically named with UpperCamelCase. Instances are typically named with lowerCamelCase.

## Class inheritance

One of the most valuable features of OOP and classes is "inheritance". Inheritance allows classes to "inherit" properties and methods from one another by forming "parent-child" relationships. For example, if I wanted to create classes for `Bicycle` and `Car` vehicle types, both of which have a `speed` property and the same `calcTravelTime` method that depends on `speed`, I can define how we store the `speed` property and define the `calcTravelTime` method in a parent class `Vehicle` and have `Bicycle` and `Car` classes inherit from `Vehicle` to avoid repeating code.

{% code title="class-example.js" %}

```javascript
class Vehicle {
  constructor(speed) {
    this.speed = speed;
  }
  
  calcTravelTime(distance) {
    return distance / this.speed;
  }
}

/*
 * Bicycle and Car classes "inherit" properties and methods from Vehicle class
 */

class Bicycle extends Vehicle {
  constructor(speed) {
    // The super keyword runs the constructor of the parent class
    super(speed);
  }
}

class Car extends Vehicle {
  constructor(speed) {
    super(speed);
  }
}

// Declare new Bicycle and Car instances
const bicycle = new Bicycle(10);
const car = new Car (100);

// Even though we did not define calcTravelTime in Bicycle and Car, they have the method
console.log(bicycle.calcTravelTime(100)); // 
console.log(car.calcTravelTime(100));
```

{% endcode %}

1. Notice we use the keyword `extends` to specify inheritance in JavaScript
2. Notice we use the keyword `super` in constructor methods of child classes `Bicycle` and `Car` to call the constructor method of their parent, `Vehicle`.

Try creating a local file `class-example.js` with the above code and running it with `node class-example.js`, playing around with its features to understand how classes work!
