JavaScript/OOP-classical

The heart of JavaScript's object-based approach is the linked list of objects where every object acts as a prototype for its successor. It is revealed when using the classical syntax.

Construction
There are different syntactical ways to construct objects. They are not identical, but even looking behind the scene, you will see only slight differences in their semantics. All variants create a set of key/value pairs, the properties. This set of properties composes an object.

The three language constructs literal,, and   create simple or complex objects. Such objects can be subsequently extended by assigning values to additional properties.

Functions
The 'value' part of the key/value pairs can contain not only values of primitive data types. It's also possible that they contain functions. (When functions are the value-part of a property, they are called a method.)

new
In the previous example, we defined objects containing a property with a value and another with a method. Both parts are accessible by the usual dot-notation. But they miss a smart syntactical feature: it's not possible to define their properties directly with the first invocation. Something like  or   will not run because such a syntax misses the name of the property.

We change and extend the above example to allow this syntax, the  operator in combination with parameters. To do so, we define functions (which are also objects) that contain and store variables as well as ('inner') functions/methods.

The function  takes parameters as every other function. The first letter of its name is written in uppercase, but this is only a convention and not mandatory. If the function is invoked with the  operator, in the first step, a new object is constructed. Within the function, you can refer to the new object with the keyword 'this', e.g., to store the given parameters. If, in addition, the function shall offer some functionality in the form of ('inner') functions, you define them and store a reference to them in 'this' under an arbitrary name - in the example, it is the 'show' function.

After the function is defined, you can use them via the  operator to create individual objects (instances). Such individual objects store the given arguments and offer the internally defined functions.

Please note that the  statement is different from the usual invocation of a function without the   operator:. The  is necessary to indicate that the construction of an object must be done before the body of the function can run. Without, the JavaScript engine doesn't create an object, and the use of 'this' will fail.

Predefined data types
Many predefined data types (Date, Array, ...) are defined in the above way. Therefore you can use the  operator for their creation:. The arguments are stored somewhere in the newly created object. Here, it's only a single one, a literally expressed array. It gets decomposed, and the array elements are stored. Some derived properties are computed, e.g., the, and a lot of methods are provided, e.g.,   and. All in all, the internal structure often differs from the externally visible form.

In addition to this unified syntax with  there are some syntax variants that are special according to the intended data type. E.g., for  you can use. But it's just an abbreviation for:.

Inheritance
This chapter shows different syntactical possibilities for how to arrange objects in a hierarchy.

setPrototypeOf
If you have defined independent objects, you can subsequently link them together so that they build a parent/child relationship afterward. The crucial function is. As its name suggests, the function sets one object as the prototype of another object. By this, the parent's properties, including functions, are accessible to the child.

After  is successfully executed, the child object 'extends' the parent object. It gets access to all properties of the parent object, as shown in line 12.

How does it work? Every single object contains a property named '__proto__', even if it is not mentioned anywhere in the source code. Its value refers to the object which acts as its 'parent'. Also, the 'parent' contains such a '__proto__' property, and so on. At the highest level, the value is  to flag the end of the hierarchy. All in all, it's a 'linked list' of objects. It is called the prototype chain. It is the heart of JavaScript's implementation of OOP: 'parents' act as 'prototypes' for the referencing objects - for all system objects as well as for all user-defined objects.

The JavaScript engine uses the prototype chain whenever it searches for any property. When the engine doesn't find it, it switches to the next higher level and repeats the search.

This applies in the same way to the case that a function is searched.

After line 13, the method  can be invoked by the child object, although it is defined by the parent.

new
Suppose you know in advance that one object shall act as a child of another object. In that case, the  operator offers the possibility to define the dependency from the beginning. The already existing object can be given as a parameter to the creation process. The JavaScript engine will combine this existing object with the newly creating object by the exact same mechanism, the '__proto__' property.

Object.create
This pre-known hierarchical relation can also be realized with the  method.

A distinction to class-based approaches
There are some distinctions between JavaScript's prototype-based approach and class-based approaches. One of them regarding inheritance is shown here.

After creating a prototype hierarchy and instances with one of the above methods, you can modify the 'parent' instance to manipulate all 'child' instances at once.

The statement in line 17 adds the property 'property_2' - virtually - to all instances at once. Whenever 'property_2' is acquired by a subsequent statement, the JavaScript engine will follow the prototype chain. First, in the 'child' instances, it will not find 'property_2'. But following the prototype chain, it will find it in the 'parent' instance. For the 'child' instances, it doesn't make a difference whether the property is in its own space or in its parent space.

The distinction to a class-based approach is that not only the value of the new property is added. Also, the structure of all instances is expanded: the added property hasn't existed at all before line 17.

Check object hierarchy
There are different ways to check the hierarchy of data types of any variable or value.

getPrototypeOf
The  method gives you a chance to inspect the hierarchy. It returns the parent object itself, not its data type. If you are interested in the data type of the parent, you must check the parent's data type with one of the other operators.

Or, follow the prototype chain in a flexible loop:

instanceof
The  operator tests whether the prototype chain of a variable contains the given data type. It returns a boolean value.

typeof
The  operator returns a string showing the data type of its operand. But it is limited to detect only certain data types respectively their parent object. Possible return values are: "undefined", "object", "boolean", "number", "bigint", "string", "symbol", "function".

Exercises

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