Classes in ES6

Well in other languages, we use classes to create objects and provide inheritance. In JavaScript we use function to create objects. And being able to inherit data and functionality in JavaScript happens through prototypal inheritance. So JavaScript still uses functions and prototypal inheritance under the hood. JavaScript is not a class based language. It uses functions to create objects and links objects together by prototypal inheritance. JavaScript classes are just the thin mirage over regular functions and prototypal inheritance.

Inheritance is like one objects trying to access methods and properties of other object. Whenever you create a JavaScript object, JavaScript engine automatically attaches object with some hidden properties and functions so these come via prototype.

let arr=["Divya", "Akshay"];
let object={
name:"Divyanshi",
city:"Lucknow",
getIntro(){
console.log(this.name + "from" + this.city); 
}
}
let object2{
name:"Aditya"
}
//Never do this 
object2.__proto__=object

//when you try to access any property first of all it checks in the top of the main object if it does find it, it goes to the proto and if it doesn't find it inside proto it goes inside the proto of proto and thats how it goes throughout the chain. So this is whole prototype chain. and this is how object2 inherits from object this is called prototype inheritance.
function fun(){
//
}
arr.__proto__
//is same as array prototype
arr.__proto__.__proto__
// is same as object prototype
arr.__proto__.__proto__.__proto__
//null
obj.__proto__
//is same as Object prototype
obj.__proto__.__proto__
//is same as null
fun.__proto__
//is same as Function prototype
fun.__proto__.__proto__
//is same as Object prototype

ES5 "Class" Recap

function Plane(numEngines) {
  this.numEngines = numEngines;
  this.enginesActive = false;
}

// methods "inherited" by all instances
Plane.prototype.startEngines = function () {
  console.log('starting engines...');
  this.enginesActive = true;
};

var richardsPlane = new Plane(1);
richardsPlane.startEngines();

var jamesPlane = new Plane(4);
jamesPlane.startEngines();

In the code above, the Plane function is a constructor function that will create new Plane objects. The data for a specific Plane object is passed to the Plane function and is set on the object. Methods that are "inherited" by each Plane object are placed on the Plane.prototype object. Then richardsPlane is created with one engine while jamesPlane is created with 4 engines. Both objects, however, use the same startEngines method to activate their respective engines.

Things to note:

the constructor function is called with the new keyword the constructor function, by convention, starts with a capital letter the constructor function controls the setting of data on the objects that will be created "inherited" methods are placed on the constructor function's prototype object

ES6 Classes Here's what that same Plane class would look like if it were written using the new class syntax:

class Plane {
  constructor(numEngines) { // new and special method that exists in a class and is used to initialize new objects. 
    this.numEngines = numEngines;
    this.enginesActive = false;
  }

  startEngines() {
    console.log('starting engines…');
    this.enginesActive = true;
  }
}
typeof Plane;
Returns: function

Static methods To add a static method, the keyword static is placed in front of the method name. Look at the badWeather() method in the code below. Static class methods are defined on the class itself. You cannot call a static method on an object, only on an object class.

class Plane {
  constructor(numEngines) {
    this.numEngines = numEngines;
    this.enginesActive = false;
  }

  static badWeather(planes) {
    for (plane of planes) {
      plane.enginesActive = false;
    }
  }

  startEngines() {
    console.log('starting engines…');
    this.enginesActive = true;
  }
}

See how badWeather() has the word static in front of it while startEngines() doesn't? That makes badWeather() a method that's accessed directly on the Plane class, so you can call it like this:

Plane.badWeather([plane1, plane2, plane3]);

Benefits of classes

  • Less setup
  • There's a lot less code that you need to write to create a function
  • Clearly defined constructor function
  • Inside the class definition, you can clearly specify the constructor function.
  • Everything's contained
  • All code that's needed for the class is contained in the class declaration. Instead of having the constructor function in one place, then adding methods to the prototype one-by-one, you can do everything all at once!

Things to look out for when using classes

  1. class is not magic The class keyword brings with it a lot of mental constructs from other, class-based languages. It doesn't magically add this functionality to JavaScript classes.
  2. class is a mirage over prototypal inheritance We've said this many times before, but under the hood, a JavaScript class just uses prototypal inheritance.
  3. Using classes requires the use of new When creating a new instance of a JavaScript class, the new keyword must be used
class Toy {
   ...
}
const myToy1 = Toy(); // throws an error
Uncaught TypeError: Class constructor Toy cannot be invoked without 'new'

but, adding the new keyword fixes the problem

const myToy2 = new Toy(); // this works!

Subclasses with ES6 Now that we've looked at creating classes in JavaScript. Let's use the new super and extends keywords to extend a class.

class Tree {
  constructor(size = '10', leaves = {spring: 'green', summer: 'green', fall: 'orange', winter: null}) {
    this.size = size;
    this.leaves = leaves;
    this.leafColor = null;
  }

  changeSeason(season) {
    this.leafColor = this.leaves[season];
    if (season === 'spring') {
      this.size += 1;
    }
  }
}

class Maple extends Tree {
  constructor(syrupQty = 15, size, leaves) {
    super(size, leaves);
    this.syrupQty = syrupQty;
  }

  changeSeason(season) {
    super.changeSeason(season);
    if (season === 'spring') {
      this.syrupQty += 1;
    }
  }

  gatherSyrup() {
    this.syrupQty -= 3;
  }
}

const myMaple = new Maple(15, 5);
myMaple.changeSeason('fall');
myMaple.gatherSyrup();
myMaple.changeSeason('spring');

Both Tree and Maple are JavaScript classes. The Maple class is a "subclass" of Tree and uses the extends keyword to set itself as a "subclass". To get from the "subclass" to the parent class, the super keyword is used. Did you notice that super was used in two different ways? In Maple's constructor method, super is used as a function. In Maple's changeSeason() method, super is used as an object!

The extends keyword is used to create a child class of another class (parent).The child class inherits all the methods from another class. Inheritance is useful for code reusability: reuse properties and methods of an existing class when you create a new class. The super() method refers to the parent class. By calling the super() method in the constructor method, we call the parent's constructor method and gets access to the parent's properties and methods.