Categories
Modern JavaScript

Best of Modern JavaScript — Child Classes

Spread the love

Since 2015, JavaScript has improved immensely.

It’s much more pleasant to use it now than ever.

In this article, we’ll look at how to define classes with JavaScript.

Computed Method Names

We can add methods with computed property names.

For example, we can write:

class Foo {
  ['foo' + 'Bar']() {}
}

We pass an expression that returns a string or symbol into the square brackets to create a method with the given identifier.

We can also pass in a symbol by writing:

class Foo {
  [Symbol.iterator]() {
    //...
  }
}

Generator Methods

We can add generator methods to a class.

For example, we can write:

class Iterable {
  constructor(arr) {
    this.arr = arr;
  } 

  *[Symbol.iterator]() {
    for (const a of this.arr) {
      yield a;
    }
  }
}

We create an Iterable class with the constructor and a method with the Symbol.iterator method.

This makes our Iterable instance iterable.

The method is a generator as indicated by the * symbol.

And we use yield to return and pause each item.

We can then use it with a for-of loop by writing:

class Iterable {
  constructor(arr) {
    this.arr = arr;
  }

  *[Symbol.iterator]() {
    for (const a of this.arr) {
      yield a;
    }
  }
}

for (const x of new Iterable(['foo', 'bar', 'baz'])) {
  console.log(x);
}

And we get each entry of the array we passed in logged.

Subclassing

We can create subclasses from base classes.

The extends keyword lets us create subclasses.

For example, we can write:

class Person {
  constructor(name) {
    this.name = name;
  }
  toString() {
    return `(${this.name})`;
  }
}

class Employee extends Person {
  constructor(name, title) {
    super(name);
    this.title = title;
  }
  toString() {
    return `(${super.toString()}, ${this.title})`;
  }
}

We created the Employee class with the extends keyword to create a subclass of Person .

In the constructor of Employee , we call super to call the Person constructor from there.

This is required before we access this in the subclass.

We set the this.title property with the title parameter’s value.

In the toString method, we call super.toString to call toString of the Person instance.

If we create an instance of Employee , we can check the class that it’s created from.

For instance, we can write:

const emp = new Employee('jane', 'waitress');
console.log(emp instanceof Person);
console.log(emp instanceof Employee);

They both return true and as we expect.

Person is the base class and Employee is the child class.

The Prototype of a Subclass is the Superclass

The class syntax is just a convenient way to create constructors, so it sticks to the prototypical inheritance model.

The prototype of a subclass is the superclass.

If we have:

class Person {
  constructor(name) {
    this.name = name;
  }
  toString() {
    return `(${this.name})`;
  }
}

class Employee extends Person {
  constructor(name, title) {
    super(name);
    this.title = title;
  }
  toString() {
    return `(${super.toString()}, ${this.title})`;
  }
}

Then:

console.log(Object.getPrototypeOf(Employee) === Person)

logs true .

Static properties are inherited from the base class by the child class.

For example, if we have:

class Foo {
  static baz() {
    return 'baz';
  }
}

class Bar extends Foo {}

Then we can call:

Bar.baz()

We can also call static methods in child classes:

class Foo {
  static baz() {
    return 'baz';
  }
}

class Bar extends Foo {
  static baz() {
    return `child ${super.baz()}`;
  }
}

Conclusion

We can add computed method names, static members, and get parent class members from child classes.

Leave a Reply

Your email address will not be published. Required fields are marked *