JavaScript/OOP-classes



The popularity of class-based programming languages inspires the JavaScript community to cover its prototype-based implementation of OOP with a syntax that mimics a class-based approach. EcmaScript 2015 (ES6) gets expanded by corresponding key words like 'class' or 'extend'.

Classes are templates or 'blueprints' to create objects. They encapsulate their data and contain functions to work on it.

Creation

edit
class Person {
  // Class body is always implicitly in "use strict" mode
  constructor(name) {
    // Data. Declarations like 'let x = 0' are not necessary.
    this.name = name;
  }
  // functionality
  showName() {
    return "My name is: " + this.name;
  }
}

const ada = new Person("Lovelace");
alert(ada.showName());

The keyword class introduces the class definition. In the example, Person is the class name. It is followed by the class body that is enclosed in curly brackets { }, lines 1 - 11. Within the body, there is a special method constructor. This function is invoked during class creation. In the example, it takes one argument, the name of a person. Within constructor this argument is stored internally by using the keyword 'this'. The class offers only one functionality: the showName method.

Static properties and methods

edit

The above syntax shows how to handle properties and methods of individual objects (instances - like 'ada' in the above example). It's also possible to define properties and methods that are not available at the level of individual objects but at the class level - 'Person' in the above example. They are introduced by the keyword static.

class Person {
  constructor(name) {
    // data
    this.name = name;
  }

  static className = "The PERSON Class";
  static showClassName() {return "The name of this class is: " + this.className};

  showName() {
    return "My name is: " + this.name;
  }
}

const ada = new Person("Lovelace");
// alert(ada.showClassName()); // Error!
alert(Person.showClassName());

Lines 7 and 8 use the 'static' keyword. Therefore the property and method are NOT available for instances, only for the class altogether.

Class methods can be offered as properties. This frees the programmer to distinguish between access to methods - via parenthesis () - and properties. The keyword get introduces the feature.

class Person {
  constructor(name) {
    this.name = name;
  }
  // getter
  get showTheName() {
    return this.showName();
  }
  // 'regular' method
  showName() {
    return "My name is: " + this.name;
  }
}

const ada = new Person("Lovelace");
// NO parenthesis ()
alert(ada.showTheName);

Inheritance

edit

Next, we define a hierarchy of classes. This is done with the keyword extends. In the example, Employee is a sub-class of Person and has access to all its properties and methods.

class Person {
  constructor(name) {
    this.name = name;
  }
  // method
  showName() {
    return "My name is: " + this.name;
  }
}
class Employee extends Person {
  constructor(name, company) {
    super(name);
    this.company = company;
  }
  // method
  showCompany() {
    return "I, " + this.name + ", work at the company " + this.company;
  }
}

const henry = new Employee("Henry Miller", "ACME Inc.");
alert(henry.showCompany());
alert(henry.showName());     // method of the parent class

Line 12 invokes the constructor of the parent class. This is necessary because the parent's constructor creates 'this'.

Access control

edit

By default, class properties and methods are accessible. You can hide them by using a hash # as the first character of their name.

class Person {

  // two hidden properties (sometimes called 'private fields')
  #firstName;
  #lastName;

  constructor(firstName, lastName) {
    this.#firstName = firstName;
    this.#lastName = lastName;
    // one public property
    this.name = lastName + ", " + firstName;
  }
  #showName() {  // hidden method
    alert("My name is " + this.name);
  }
}

const ada = new Person("Ada", "Lovelace");
alert(ada.name);        // ok
alert(ada.firstName);   // undefined
alert(ada.#firstName);  // undeclared private field

alert(ada.#showName()); // undeclared private method

Polymorphism

edit

If a method name is used in a 'parent' class as well as in a 'child' class, the JavaScript engine invokes that one of the correlating class.

class Person {
  constructor(name) {
    this.name = name;
  }
  // method name is used also in 'child'
  showName() {
    return "My name is: " + this.name;
  }
}
class Employee extends Person {
  constructor(name, company) {
    super(name);
    this.company = company;
  }
  // same method name as in 'parent'
  showName() {
    return "My name is: " + this.name + ". I'm working at the company " + this.company;
  }
}

const henry = new Employee("Henry Miller", "ACME Inc.");
alert(henry.showName());       // from Employee

const nextPerson = new Person("John");
alert(nextPerson.showName());  // from Person

The example defines and uses two different methods showName.

this

edit

this is not a variable or an object; it's a keyword. Depending on the context, it refers to different things. In the context of class definitions, it refers to the class itself, e.g., this.city = "Nairobi" refers to the property 'city' of the current class.

When this is used at the top level of a file (in other words: outside of any function or object), it refers to the global object. In a function, in strict mode, this is undefined. In a DOM event, it refers to the element that received the event.

Exercises

edit
... are available on another page (click here).

See also

edit