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
editclass 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
editThe 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.
get
editClass 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
editNext, 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
editBy 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
editIf 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
editthis
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.