JavaScript Objects and their Prototypes.

Contents

Introduction

Arguably the most important Object-Oriented Programming (OOP) language is Java, announced in 1995. Shortly after Java's announcement JavaScript was introduced as a client-side language running in internet browsers. Although its name suggests that it is a version of Java, it is not: JavaScript is an autonomous language. Particularly, JavaScript's handling of objects differs from Java's in that JavaScript's objects inherit properties and methods by means of prototypes, while Java's instances inherit properties from their class.

Javascript's prototype inheritance is rather abstruse and to bolster my understanding of it I wrote these notes. When I wrote them I had knowledge of basic JavaScript and most of the programming constructs that JS shares with other languages. So, the latter topics are not treated below. The exact JavaScript syntax can be found, for instance, here (Guide) or here (Reference). Mainly the version of JavaScript that is known as ecmascript 3 will be used. Later versions of ecmascript are fully compatible with version 3.

The main source for these notes was JavaScript: The Definitive Guide by David Flanagan, O'Reilly, 4th edition, 2002 (known as the "Rhino book" because of the Rhinoceros on its cover). Prototype chains and inheritance will be discussed below in more detail than in the 4th edition of the Rhino book. The first version of the present notes date from before the Spring of 2011 when the 6th edition of the Rhino book appeared. The 6th edition is completely different from the 4th edition, the 6th edition is a new— and even better—book. It contains much more material explaining prototype-based inheritance, use of the keyword this, etc. Although the 6th edition makes the present notes somewhat redundant, they are not altogether useless, because much of the material below is found scattered through the 1100 pages of sixth edition of the Rhino book, whereas the present text concentrates solely on JavaScript's prototype inheritance.

With regard to the format of the present notes: They are written in what used to be called "dynamic html". Also the table of contents is dynamic. This means that part of the text is built by the execution of JS code snippets during browsing. The disadvantage of this is that reading the notes requires a browser that supports JavaScript. The advantage is that no typing or copying errors can creep in.

Code snippets are given internally as follows,

<pre>
   A code snippet
</pre>

followed by
<script>
   The same code snippet
</script>

The code between <pre> and </pre> is listed in the present html text and the very same code between <script> and </script> is executed with its output listed in this text in bold face green. The output of the code snippets is performed by the function:
function println(x) {
       document.writeln("<span class='green'>" +  x + "</span><br>");
}

The printing of the members of an object is by the function:
function printObj(obj) {
   for (key in obj) {
       if (obj.hasOwnProperty(key)) println(key + ": " + obj[key]);
   }
}

This function loops over the non-inherited (own) properties of the JavaScript object obj.   To keep `for (key in obj)` loops within bounds, many built-in JavaScript objects have the attribute "nonenumerable". These objects are not listed either.

Most object members in the examples will have simple string values. A string is an immutable sequence of arbitrary characters enclosed by single or double quotes and is easy to assign and recognize. The emphasis of these notes being on prototype inheritance, examples with more complex syntactical features of JavaScript would be distracting.

To contents

Brief overview

As in all object-oriented languages, a JS object is a collection of pairs consisting of a name (the key) and a value. The name of the object and of its keys obey the normal rules for JS identifiers (are case-sensitive, first character is a letter, underscore, or a dollar sign). A key is bound to a value that can be anything in the JavaScript language (a string, a boolean, a number, or an object). The key-value pairs are referred to as the members of the object. When the value is a function, it is referred to as a method of the object. Non-function members are usually called properties.

The full name of a member starts with the name of the object to which it belongs and is followed by one or more refinements. A refinement is a period followed by the name of a member, a key (which again may be bound to any JS entity). This construction of names is as is usual in object-oriented languages. Long chains of refinements can be found in JavaScript programs. Usually they describe a hierarchical structure. When grandMa has a son Joe and Joe has a daughter Emma, with Emma having the property age (her age, a natural number), then

 grandMa.Joe.Emma.age = 13; 

is JavaScript's way of stating that grandMa's grandchild Emma (daughter of Joe) has become 13 years old. Here grandMa, Joe, Emma, and age are object keys and 13 is a number.

JavaScript does not only posses many aspects of OOP languages, but also of functional languages. For instance, the right-hand side of an assignment statement may be a function—a function is handled as any other JS entity (a JS function is a "first class citizen"):

var Constr = function() {};

[The keyword var declares a variable to be local to a function. In the context of the present notes all variables outside functions are in global space so that var may be omitted, but it is good practice never to forget var.]

JavaScript knows five kinds of primitives, non-objects. Namely: numbers, strings, booleans (true or false), null, undefined. All other JS entities are of type object, characterized by having key-value pairs. It is useful to distinguish different types of objects: functions, arrays, literals, and "object objects" (the latter being non-primitives that are not of type function, array, or literal).

Many JavaScript objects are defined by application of the operator new operating on a function. This function is called the constructor of the object. Thus, for example, the object named obj may be created as follows:

var obj = new Constr();

The constructor (the function named here Constr, but it can have any name) performs a role similar to a class definition in other object-oriented languages. In analogy the object obj on the left-hand side of new is called an instance of class Constr. It is common practice to let the names of constructors (operands of new) start with an uppercase letter and names of other function with a lowercase letter.

In Sec. 5.1 it will be shown how the application of new results in two kinds of members (properties or methods) of obj. The first kind are read-only members that are referred to as "inherited". Members of the the second kind are called "own properties". They have read-write access and may be are created during the execution of Constr.

To contents

Object Literals

Besides the definition of an object by application of the operator new, there is a more direct way of of creating an object (which is not a function or array), namely as an object literal. This is simply a set of key-value pairs that is reminiscent of associative arrays in other languages. JavaScript does not have associative arrays per se, object literals serve this role.

As an example, the object literal objLit is defined with two string-valued properties, named key1 and key2 with values the strings val1 and val2, respectively:

var objLit = {key1: 'val1',
              key2: 'val2'};
printObj(objLit);

This prints:
The properties key1 and key2 are own (non-inherited) properties of objLit.

The members of an object may be accessed by an alternative to the dot notation: the square bracket notation. A property of an object can be accessed by square brackets surrounding a quoted key, i.e., objLit["key1"] vs. objLit.key1. For example,

println('objLit["key1"] has the value ' + '"' + objLit["key1"] + '"');
println('objLit.key1 has the value ' + '"' + objLit.key1 + '"');

prints:
[The operator + concatenates strings. ]

To an existing object a method may be added as follows:

objLit.f = function() {println("Hello, world")};

The method f() is invoked as:
objLit.f()

This prints:

The statement:

for (var key in object){...}

loops over (most of) the keys of an object. The loop is over inherited as well as own properties. The names of the members (keys) are assigned as string values to the JS variable key. (Therefore the variable name key must not be within quotes when accessed.) Many built-in JS objects have long lists of properties that hardly ever change (or do not change at all if they lack the writable attribute). In order not to clog up the "for-in" loops with these long lists, many properties carry the nonenumerable attribute, meaning that they are skipped in "for-in" loops. In later versions of JavaScript this attribute can be set, in ecmascript 3 this is not possible.

In the following example litObj is defined and a for-in loop lists its properties. The example ends with a call to a method of litObj. The code snippet:

var litObj = {arr: [1,2,3],
              fnc: function(s1, s2){println(s1+s2)},
              obj: {key1: "X", key2: "Y"}
             };
for (var key in litObj){
   println(key + ': ' + litObj[key]);
}
var s1 = "Hi ";
var s2 = "there!"
litObj.fnc(s1, s2);

prints:

[Note the for-in loop in the body of the function printObj listed in the introduction. In printObj inherited objects are filtered out, only own properties are printed.]

To contents

Primitive and compound entities

Assignment of a primitive entity (number, string, or boolean) to a variable causes a copy of the value of the primitive entity. If one introduces var a="XYZ" and var b=a, it is found that both a and b are bound to a private copy of the string "XYZ". A change of a's value does not affect b's value and conversely. This is known as assignment by value.

Variables with a value that is a compound entity (object, array, or function) are assigned by name. Assignment of a variable to a compound entity gives the variable as value the name of the memory block where the compound value is stored. The variable becomes a pointer to this memory block. Two variables bound to the same compound entity are said to be each other's alias. Aliases share keys and values. The advantage of assignment by name is that it does not require copying or duplication of data, which obviously would require extra memory and extra CPU cycles. Assignment by name is therefore more efficient than assignment by value.

To illustrate changes in aliases, two compound entities objA and objB are introduced that are each other's alias:

var  objA = {a: ['AAA']}        // value of objA.a is array with one element 
var  objB = objA;               // objB is an alias of objA (same keys, same values).

Below the universal method hasOwnProperty will be introduced that distinguishes between own and inherited properties. One expects an aliased property to be non-inherited (own) and indeed:
println(objB.hasOwnProperty('a'))

prints

Change now objB.a and look at objA.a:
objB.a = ['XYZ'];               // reassign element objB.a
println('objA.a == ' + objA.a); // reassignment of objB.a changes objA.a

This prints:
Although objA.a did not appear explicitly in an assignment after it was created, it changed. Likewise, addition of members are seen by all aliases:
objB.b = 123;                   // New member objB.b
println('objA.b == ' + objA.b); // New member of objA

With output:
In conclusion: changes of values of members (or addition of members) in one alias are automatically followed by equally named members of other aliases.

The same rule holds for arrays. Change in alias B:

var A = [1,2,3];
var B = A;
B.push(4)               
println('Array A: ' + A); 

gives change in original array A:

When one of the aliases is reconstructed—is bound to another (possibly new) object—the binding of the others stay to the old (non-reconstructed) object. As an example, consider 3 aliases objA, objB, and objC. Reconstruct objB:

var objA = {a: 'I', b: 'II', c: 'III'};
var objB = objA;
var objC = objA;
println('Is objC alias of objB  before reconstruction of objB? ' + (objC === objB)); 
objB = {aa: 'III', bb: 'IV', cc:'V'}          // Reconstruct objB           
println('Is objC alias of objB after reconstruction of objB? ' + (objC === objB)); 
println('Is objC alias of objA after reconstruction of objB? ' + (objC === objA));

Output of this snippet is:

Clearly, by the assignment of objB to a new object aliases are broken. Only objA and objC remain each others alias, bound to the original object.

Again, the same rule holds for arrays:

var A = [1,2,3];
var B = A;              // B and A are aliases
B = [3, 2, 1];          // Reassign B       
println('Array A: ' + A); 

Reassignment of B gives no change in original array A:

Parenthetically, it is of interest to point out that JavaScript does not know "free" global variables. Global variables are keys of a master object, even when this is not apparent. In html pages read by a webbrowser the master object is named window. The declaration var a adds the key a to window. As an example two variables are created. The second is an explicit member of window and the first is not.

var a =  "AAA";                       // Implicit member
window.b = "BBB";                     // Explicit member
println('window.a == ' + window.a);   // Print as explicit member
println('b == ' + b);                 // Print as implicit member

This has output:
It shows that a and b are both members of window. The stem window. may be omitted, it is the default for global variables.

Aliasing is often employed to give short synonyms to long variable names. One must be careful in doing this, because aliasing does not work for primitives. Consider the following example pertaining to a weather station:

var  measurements = {station: {temperature: [60, 70, 80],
                               pressure: [1.0, 1.2, 1.4]}};
var t = measurements.station.temperature;      // short-hand alias for an entire array
for (var i=0; i<t.length; i++) {
    p    = measurements.station.pressure[i];   // short-hand alias for an array element
    t[i] = ((t[i] - 32)*5/9).toFixed(1);       // From Fahrenheit to Celsius
    p    = p*1.01325;                          // From bar to atm
}
// Print the array elements with index 2:
println(measurements.station.temperature[2] + "   // updated value");
println(measurements.station.pressure[2]    + "   // original value");

This snippet prints:
An assignment of p does not update measurements.barometer.pressure[2], because p has a primitive value (a number) and is not an alias of the array element. The assignment of the array element t[2] does update the array measurements.barometer.temperature, a non-primitive.

Primitive and non-primitive values have also different scopes as function parameters. Consider a function with a primitive parameter o that is modified inside the function:

var o = 2;   //primitive (a number)
var change = function(o){
    o = o + 10;      // passed by value
}
change(o);
println(o);

prints:
In other words, modifications of primitives made inside functions are not visible outside the function, the primitive has local scope. Compare this with the following very similar piece of code, where o is a one-element array literal (a non-primitive) and remember that JavaScript starts indexing arrays at 0:
var o = [2];   // o refers to an array of one element
var change = function(o) {
    o[0] = o[0] + 10;  // passed by name
}
change(o);
println(o);

prints:
Clearly, the placing of square brackets around o makes a difference, it transforms o from a primitive to an array object and gives o global scope inside the function change().

To contents

Object objects

Objects that are not array, function, object string, or object literal will be referred to as "object objects" by lack of a better name. It was shown earlier that the object objects are constructed by means of the operator new acting on an arbitrarily named function, the constructor.

A function, as any object, has members. By default, all JavaScript functions receive a member named prototype at their creation. By default its value is an object. Thus, for example,

var Constr = function() {}; 

gives the simultaneous creation of the object Constr.prototype.

Because the "prototype member of a constructor function" will be seen to play a pivotal role in JavaScript's inheritance, we find it convenient to give it the shorter name "progenitor", although this name is somewhat idiosyncratic as it is not in general use. As will be shown below an instance does not necessarily inherit from an object with key prototype and therefore a separate term seems useful for the object from which an instance inherits properties and methods. Readers who don't like the term progenitor can substitute prototype and be aware that a prototype has not always the key prototype.

The prototype member of a function that is not a constructor, although it exists, does not play any role. The prototype member only becomes important when the function is a constructor (appears as an operand of new). In that case all key-value pairs of the prototype (the progenitor) are inherited by all instances of the constructor. In other words, all instances have read-access to all members of their progenitor. For example,

Constr.prototype.age = 43;
var obj = new Constr();           // An instance that inherits from Constr.prototype
println("My age is: " + obj.age)

prints

When Constr.prototype is augmented by a function, the function becomes a method of the instance obj.
Constr.prototype.f = function(){this.str = "XYZ";};   // Add member
obj.f();                                              // Execute inherited method of instance
println(obj.str )                                     // Print property of instance

This prints
The keyword this in the body of the method is a pseudonym of the object that inherits the method, in this case obj. We will return to the keyword this in Chapter 7.

The operator new

The operator new creates an instance by operation on a constructor function C(). The instance inherits from its progenitor C.prototype.  [Objects created by new were earlier referred to as "object objects". This duplication in the name will be skipped from hereon when there is no possibility of confusion with other types of objects.]   Consider the following pseudo-code for a constructor function:
var C = function(args) {
       this.a = ...;
       this.b = ...;
       ....
       More executable statements
       ....
}
C.prototype.x = ...;
C.prototype.y = ...;
....

The following statement creates the object objC, an instance of a class generated by the constructor C():
var objC = new C(args);

Here new has three effects:
  1. It creates the object objC; if objC exists prior to new, it is overridden.
  2. It invokes the constructor function C(args) and executes the statements inside its body (using args as arguments). It is during this execution that values are assigned to this.a, this.b, etc., where this is replaced by the name of the left-hand side of new, in this case objC. Own properties of objC are created:
    objC.a = ...;
    objC.b = ...;
    ....
    

    These assignments follow the usual rule (by name for a non-primitive right-hand side, by value for a primitive one).
  3. It stores a hidden pointer (a member of objC) to its progenitor C.prototype.
The pointer from object objC to its progenitor is followed when the inherited properties with keys x, y, ... are accessed (in read mode): the actual values of C.prototype.x, C.prototype.y, ... are returned. This is the precise meaning of "inheriting" the properties of the progenitor C.prototype. (In Chapter 8 it will be shown that inheriting may not only from "parents", but also from "grandparents", or even from arbitrary "ancestors"). The property names (keys) x, y, .. stay the same.

The following rule is central to prototype inheritance. Any inherited member key of objC points to the equally named member key of its progenitor:

objC.key → C.prototype.key → Value

where Value is an object or primitive. Because most of the inheritance mechanism occurs behind the scenes, this rule is not immediately obvious.

In summary: an instance object created by new has two kind of members: (i) inherited from its progenitor and (ii) non-inherited (own), created by assignments to this in its constructor or added later.

Inherited members of an instance are dynamic in the sense that that they point to the equally named members of its progenitor, even after the latter are created or changed. All instances of a constructor follow changes in their progenitor during execution. This will be considered in more detail below. Object members can be created dynamically. Look, for example, at the method obj.f() in the snippet above. The method f() was added to obj's progenitor Constr.prototype after obj was created. This is unlike the relationship between classes and instances in many class-based OOP languages where inheritance rules are settled statically (at compile time, before execution). In view of the fact that inherited properties of an object can be added and overridden dynamically through changes in the prototype property of its constructor, JavaScript is referred to as a prototype-based language rather than a class-based language.

When an inherited member is overridden, or a new member (key/value pair) is added, the member becomes an "own property" of the instance:

var C = function() {};
C.prototype.prop = "Abracadabra";
instance_C = new C;
println('"' + instance_C.prop + '" is own? ' +  instance_C.hasOwnProperty("prop"));
instance_C.prop = "No magic, please";          // Override inherited property
println('"' + instance_C.prop + '" is own? ' +  instance_C.hasOwnProperty("prop"));

This prints:

In case of a name clash in reading an instance property, an own property takes precedence over an inherited property.

All objects have hidden members that are inherited automatically. JavaScript has a built-in master constructor function with a prototype from which all objects inherit automatically. This function is called Object() and members of Object.prototype are inherited by all JS objects. For example, all objects inherit the method Object.prototype.hasOwnProperty(arg). This method returns true or false depending on whether arg is own or inherited.

An arbitrary object object may be prepared from the built-in master constructor (which, despite its name, is a function):

arb_obj = new Object();
println(typeof arb_obj);

with output:

To contents

The prototype property

It was seen earlier that creation of a function F() entails creation of F.prototype. Now other object types, besides functions, will be inspected to see if they receive automatically a member named prototype.

First check an object literal:

var  f  = {};
if (f.prototype) println('prototype exists'); else println('prototype does not exist');

prints:
[An undefined object has value false.]

Do the same check for an array:
var  f  = [];
if (f.prototype) println('prototype exists'); else println('prototype does not exist');

prints:

An object object:
var  f  = new Object();
if (f.prototype) println('prototype exists'); else println('prototype does not exist');

prints:

and, finally, for good measure, a function:
var  f  = function(){};
if (f.prototype) println('prototype exists'); else println('prototype does not exist');

prints:

Conclusion: by default the member prototype of a non-function object is undefined.

It is possible, of course, to create a property named prototype for any non-function object, prototype is not a reserved word. This can be done by adding the key prototype to an object and assigning a value to it. However, introduction of a prototype key for a non-function is not a good idea because it may easily give rise to confusion.

To contents

prototype.constructor

By default C.prototype has an automatic member named constructor. The value of constructor is the function C() itself:
var C = function() {var x = 'String assigned in body';};
println(C.prototype.constructor);

prints:

Let us verify that C.prototype is an object object and that C.prototype.constructor is a function object. This is done by the JS operator typeof:
println('C.prototype is of type ' + typeof C.prototype);
println('C.prototype.constructor is of type ' + typeof C.prototype.constructor);

prints:

Because JS is a functional language, functions are ordinary JS entities that can be compared by the operator ===. Hence, the code

var C = function() {var x = 'String assigned in body';};
if (C === C.prototype.constructor) println(true) else println(false);

prints:

Let objC be an instance of C(). By inheritance, objC.constructor.prototype exists. Thus, existence of C.prototype.constructor implies existence of objC.constructor.prototype. The latter object has the same value as C.prototype. However, the two objects are not aliases. Among aliases the relation is democratic: a change in one is a change in all. Inheritance is intrinsically hierarchical: a change in an instance is not followed by the same change in its progenitor.

As an illustration, the smallest possible constructor and an instance are defined:

var C = function() {};
var objC = new C();

It is confirmed that the inherited property objC.constructor and the constructor C are the same:
if (objC.constructor === C) println("true"); else println("false");

prints:

For good measure we verify the same for the prototype members:
if(objC.constructor.prototype === C.prototype)
             println("true"); else println("false");

prints:

It is evident that a change of a member of an instance will not cause a change in the corresponding member of the progenitor. If it would, it would bring about a change in all instances of the progenitor. So, the following example is probably superfluous: Change an instance and print it together with the corresponding member of its progenitor:

objC.constructor = 'New';
println('objC.constructor = ' + objC.constructor);
println('C.prototype.constructor = ' + C.prototype.constructor);

This gives:
Above it was shown that objC.constructor has now changed from an inherited to an own property.

Though by default objC.constructor.prototype exists, the existence of objC.prototype.constructor is unlikely, because objC is not a function and by default does not posses the member prototype. The JS rules, such as for example the fact that objC.constructor.prototype.constructor and C() are the same, are sometimes dizzying.

The constructor property can be used to determine the type of a variable. For instance, arrays have the global, built-in, constructor Array() (a function). Any array inherits properties from Array.prototype, including the member constructor, the same as Array(). Thus, if the expression (a.constructor === Array) has value true, a is an array. Indeed, the snippet:

var a = [];
println(a.constructor === Array);

prints:

Likewise, functions have the global, built-in, constructor function Function() and hence:

var f = function() {}
println(f.constructor === Function);

prints
[Although the variable names Array and Function are not formally reserved, it is good programming practice not to assign the names to other objects, or to rename the corresponding global objects.]

To contents

Effects of changes in the prototype

Earlier it was discussed that prototype inheritance is dynamic. In this section examples will be given how the inherited members of an instance follow changes within its progenitor. Changes are followed even when they are introduced after the creation of the instance. If a prototype is replaced in its entirety after an instance is created, the link from the instance to the prototype is broken and the prototype is no longer the progenitor of the instance, that is, the instance does no longer inherit from the (replaced) prototype. If an instance is created after the prototype is replaced, the replaced prototype is the progenitor of the newly created instance, i.e. it inherits from the replaced prototype.

As a first example we add two new members to the progenitor C.prototype after the instance objC is created:

var C = function() {str = "body of constructor"};
objC = new C();
C.prototype.inheritedString = "funny string";
C.prototype.emptyFunction   = function fnc() {};


The new members are indeed inherited by the instance objC as is the existing member constructor:
println(objC.constructor);
println(objC.inheritedString);
println(objC.emptyFunction);

prints:

This confirms that the instance objC inherits properties of its progenitor C.prototype added after creation of the instance. The automatic member constructor is not affected by the addition.

In the second example the whole of C.prototype is replaced by the object literal objLit, again after new has been executed.

var objLit  = {constructor:  "This is the new C.prototype.constructor",
               inheritedString:  "odd string"};
var C = function () {str = "The old constructor"};
C.prototype.old = "old value";
var objC = new C();
C.prototype = objLit;           // Replace C.prototype
println("I: Old inherited? " + objC.old);
println("II: The new constructor: " + C.prototype.constructor);               
println("III: The inherited  constructor: " + objC.constructor);
println("IV: Added member inherited? " + objC.inheritedString)

prints:

Print statements I and III show that objC, after replacement of its progenitor C.prototype, still possesses the properties inherited at the time new was executed. This means that the value of the original progenitor C.prototype is preserved somewhere. Print statement IV shows that a total replacement of the progenitor C.prototype does not give a new progenitor for existing instances, they inherit from the old one; C.prototype is no longer the progenitor of objC. This, too, is a reason why the term "progenitor" was introduced.

The last example of this section shows the inheritance of the instance objC when it is created after C.prototype has obtained its new, nonstandard, properties:

var objLit  = {constructor:  "This is the new C.prototype.constructor",
               inheritedString:  "odd string"};
var C = function () {};
C.prototype = objLit;       // Replace C.prototype
var objC = new C();
println("I: The inherited  constructor: " + objC.constructor);
println("II: Another inherited  member: " + objC.inheritedString);

prints:

Hence, in this case C.prototype is the progenitor of objC.

In summary, objC inherits the actual values of its progenitor. It follows later changes within the progenitor, but no later total replacements.

To contents

Direct assignment of prototypes versus assignment by new

Although the following two statements create the same members of objC, they create different relationships:

var objC = new C();

and
var objC = C.prototype;

The first statement creates a "hierarchical" relationship between objC and its progenitor C.prototype, while the second makes objC an alias of C.prototype, which is a "democratic" relationship. The next two examples show the difference between the two statements. In the first example, reassignment of an inherited property does not change its value in the progenitor:
var C = function(){};
C.prototype.prop = 'AAA';
var objC = new C(); 
println('objC.prop == ' + objC.prop);
objC.prop = 'BBB';
println('objC.prop == '  +   objC.prop);
println('C.prototype.prop == '  +   C.prototype.prop);

which prints:
Hence, C.prototype.prop is not changed by a change in objC.prop, but, of course, the converse is true. The binding between objC and its progenitor C.prototype is one-directional.

The second example regards the situation that objC and C.prototype are aliases. It is shown that adding a member to objC overrides a member with the same name in C.prototype.

var C = function(){};
C.prototype.prop = 'AAA';
println('C.prototype.prop == '  +   C.prototype.prop);
var objC = C.prototype;          // Sets aliases
objC.prop = 'BBB';               // Override prop
println('C.prototype.prop == '  +   C.prototype.prop);

which prints:

Here the binding between objC and C.prototype is two-directional and it makes no longer sense to refer to C.prototype as the progenitor of objC.

To contents

The keyword this

The keyword this appears in the body of two kinds of functions.   [In JavaScript embedded in html pages, this may appear in an event handler in an html tag; it then refers to name of the tag. This use will not be discussed in the present notes]. The two kinds are:
  1. The function Fnc is a constructor, an operand of new:
    var obj = new Fnc(arg_list);
    

  2. The function fnc is a method of an object:
    obj.fnc(arg_list);
    

To contents

this inside constructors

In the body of a constructor function, this is a pseudonym for the left-hand side of the new statement, the name of the instance that is created.
var C = function() {this.prop = "This in a constructor"};
var objC = new C();
println('"' + objC.prop + '"' + " is an own property of objC? " + objC.hasOwnProperty("prop") );

The name of the object to be created may be composite, i.e., contain refinements. The composite name is substituted for this. The composite name must be declared before adding a property to it,

var scientists = {physicists: {}};           // declare object literal yielding composite name
function C(x){
      this.name = x;
}
scientists.physicists.famous = new C('Albert Einstein');   // this in C() is pseudonym of left-hand side
println("scientists.physicists.famous.name: " + scientists.physicists.famous.name);

prints:

If scientists.physicists.famous had existed, it would have been overridden by new.

To contents

this inside object methods

One may define a function-valued member of an object by an assignment:
var obj = {};
obj.nameMethod = function() {};

Here nameMethod is the name of a method of object obj. The method is invoked by obj.nameMethod().

The name of the object (of which the method is a member) is substituted for this inside the body of the method. The key of the method is not substituted.

var objC = {};
objC.nameMethod = function(x) {           // define method of objC
     this.a = x;                          // binds objC.a to the function argument x
};
objC.nameMethod('XX');                    // invoke method
println('objC.a == ' + objC.a);           // print new member

This prints:

When the name of the object is composite, this obtains the full composite name (without the method name). In the following example a new key is created and assigned a value by invocation of the method setName:

var composers = {Austrian: {eightteenthcentury: {famous: {} }}};
composers.Austrian.eightteenthcentury.famous.setName = function(x) {          
     this.name = x;
};
composers.Austrian.eightteenthcentury.famous.setName("W.A. Mozart")
println("composers.Austrian.eightteenthcentury.famous.name: " + composers.Austrian.eightteenthcentury.famous.name);

prints:

The keyword this may appear everywhere in an expression inside the body of a method. In the next example it is found on the left- and right-hand side of an assignment:

var objC = {
    a:      'AAA',                        // property of objC
    meth: function() {this.b = this.a}    // method of objC
};
println('objC.b == ' + objC.b);           // before invoking objC.method
objC.meth();
println('objC.b == ' + objC.b);           // after invoking objC.method

prints:
As for any function, a method (here objC.meth) must be called explicitly to execute its body; prior to its execution the value of objC.b is undefined.

To contents

this without context

When a function containing this is called without context, that is, as an ordinary non-nested function (not as method or through new) the name of the global object is substituted for this. This is consistent with the fact that a free function is seen as a method of the global object. The host environment of JavaScript is expected to provide such an object. In html (the markup language of the present notes) the global object is named window. The name of this object is substituted for this. In the following example f() is neither a constructor nor a method and hence this is a pseudonym for window:
var f = function(x) {
      this.a = x;
      return 'returns ' + x;
};
println(f('XXX'));
println('window.a == ' + window.a);
println('f == ' + f);
println('window.f == ' + window.f);

prints:

Observe that the call f('XXX') sets the value of window.a and returns the string "returns XXX". The function-valued variable f() is a method of the global object window; it may be accessed as f() or as window.f().

To contents

this inside nested functions

There is yet another context for this that occurs commonly in JS programs: inside the body of a function nested within another function. Schematically,
var outer = function() {
   var a = "ABCD";
   var inner = function( ){
        this.b = a;
   }
   inner();
}
outer();
println(b);


In JavaScript a nested function has access to variables of its outer (host) function.  [This is the concept of closure.]  The variable a in the snippet is an ordinary variable of the outer function and the inner function inner can access it. The question is: for which object acts this as pseudonym? Or, what is printed by this snippet, perhaps undefined?

When this is seen as a special variable with a value that depends on context and one maintains that the only allowed contexts are constructor and method, then the inner function inner(), being neither a constructor nor a method, does not offer a valid context to this. We saw earlier that when the context of this is undefined, the JavaScript standard prescribes that the name of the global object (window) is substituted. In the snippet above it means that b becomes a global variable (synonymous to window.b) and that the snippet prints:

The substitution this→window is made for appearances of this on the left- and right-hand side of assignments and leads to the counter-intuitive situation that in a (sometimes deeply) nested function global variables are manipulated, see the next example. In this example the outer function is a method of object obj, but the inner function is not a method:

var a = "A global", obj = {};
var obj.outer = function() { 
          this.a = "A local";        // sets obj.a to "A local"
          var inner = function() {
              this.b = this.a;       // sets window.b to window.a
          }
          inner();                   // invoke inner to set this.b
};
obj.outer();  // invoke outer
println("obj.a: " + obj.a);
println("window.b: " + window.b);

prints:

When a function object is nested inside a method and is named by a refinement of this [such as this.inner() nested inside obj.outer() in the snippet below], the nested object is not an inner function, but an inner method. In the snippet this.inner is assigned at the same level as this.a. Like this.a, this.inner() is a member (i.c. a method) of obj. As always, inside a method this is a pseudonym of the name of the object:

var b   = 'Global', obj = {};  // global variable
obj.outer = function() {
     this.a = "AAA";
     this.inner =  function() {this.b = this.a};
     this.inner();  // invoke obj.inner() to assign property b
};

obj.outer();   // Invoke method

println('obj.a == ' + obj.a);
println('obj.b == ' + obj.b); // Is property b of obj?
println('b own property of obj? ' + obj.hasOwnProperty("b") );
println('b   == ' + b);             // Value of global variable


prints:

To contents

The methods call() and apply()

It will be discussed in a later chapter that any JS function inherits from the built-in constructor Function(). All methods and properties of Function.prototype are available to any JS function. Two methods inherited from Function() are call() and apply(). The two are closely related. By means of call() or apply() an arbitrary function can act as a method of an arbitrary object.

In the statements:

f.call(obj) and  f.apply(obj)

the existing and arbitrary function f() is called as if it were a method of obj. This means that in the body of f() the name obj is substituted everywhere for this.

The functions call() and apply() differ in the way the arguments of f() are handled. A list of arguments can be passed to f() during invocation of f.call. The function apply has only two arguments. The first is obj and the second is an argument array.  [See any JavaScript reference for details of argument arrays.]

The action of call may be mimicked by the creation of a temporary method m() of obj which is bound to f(). Suppose the function f() has the arguments

      f(arg1, arg2, ...)

The statement
f.call(obj,arg1, arg2, ...)

is equivalent to the statements:
obj.m = f;
obj.m(arg1, arg2, ...);
delete obj.m;

[A key and its value are deleted from an object by the operator delete].

In the next example, the function f() acts as if it were a method of the object literal obj. It (i) augments obj with a new property with key b and value of obj.a. It (ii) reassigns obj.a (from its initial value "12345" to the argument "XXX"). It (iii) returns a value that is assigned to the variable z:

var obj = {a: 12345};
function f(s){
   this.b =  this.a;
   this.a =  s;
   return  s + ' ' + this.a + ' ' + this.b;
}
var z = f.call(obj, 'XXX');       // Both f and obj pre-exist
println("z = " + z);
println("<br>obj after f.call(obj):");
printObj(obj);

prints:

Let us summarize the rules.

The function f(), invoked by call or apply, can be of any kind: a global function, a method of a built-in object, a method of a user-defined object, an instance (inherited) method, and a class method.

We saw that the call f.call(null, args) is equivalent to f(args), and that f may be an instance method, say f = obj.m. When the instance method obj.m contains the keyword this in its body, the following two statements are not equivalent:

    obj.m.call(null, args) and  obj.m(args)

The second expression invokes m as a method of obj and replaces this by obj. In the first expression obj.m is executed as a method of the global object and hence this in the body of obj.m is replaced by window.

As stated above, apply has only two parameters:

   var z = f.apply(obj, arguments);

The first parameter is the name of the object to which the method f is applied. The second parameter is an argument array. The argument array is unpacked into an argument list by apply and then apply passes the unpacked list as arguments to f. Sometimes apply is used solely for unpacking an argument array.

To contents

Class methods

Above we met several examples of instance methods, the first time here. In this section it will be shown that class methods, too, can be defined in JavaScript.

Class methods are members of the constructor itself; not of its prototype. When a function handles instances of class C, it is convenient to "park" the function as a function-valued member of the constructor C, rather than in its "default parking spot", the global object window. A function C.f() is a class method of class C and is invoked by C.f(...).

As an example the class Vector is introduced. The instances of this class are 2-dimensional vectors, pairs of real numbers (x, y). They are represented as objects with keys x and y. The constructor is:

var Vector = function(xval, yval){  // Constructor for class Vector
      this.x = xval;
      this.y = yval;
};

Two unit vectors:
var e1 = new Vector(1,0);   
var e2 = new Vector(0,1);   

Mathematically, vectors can be added, which results in a new vector:
     v1 = (x1, y1),  v2 = (x2, y2)      v3 = v1 + v2 = (x1+x2, y1+y2)

This addition of two vectors can conveniently be defined as the class method Vector.add, a member of the constructor Vector. The definition of the class method with its action on two vectors is as follows:
Vector.add = function(v1, v2) {        
      return new Vector(v1.x + v2.x, v1.y + v2.y);
};

[The operator + is overloaded, it adds numbers and concatenates strings].

As an example add the two unit vectors e1 and e2:

var v3 = Vector.add(e1,e2);            // call the class method by its full name
println("v3 = " + "("+v3.x+","+v3.y+")");

This yields:

Alternatively, the function add could be written as a method for a vector instance [as Vector.prototype.add(v)]. The method would be invoked as v1.add(v2) or v2.add(v1) (one vector to be added to the other). Because vector addition treats vectors in a symmetric fashion, a class method in which the vectors appear on equal footing is more elegant than an instance method—but admittedly this is a matter of taste.

Sometimes it is convenient to create an object that has another, arbitrary, object, say p, as progenitor, i.e., the object is to inherit the properties and methods of p. This can be achieved by the following function:

function Create(p){
    function Dummy(){};             // Dummy constructor
    Dummy.prototype = p;            // Alias Dummy.prototype with p
    return new Dummy();             // Return object with p as progenitor   
};

The constructor Dummy(), which is local to the function, is not returned and is forgotten. Earlier the built-in master constructor function Object() was introduced. It is convenient to define the class method create() as a member of this master constructor:
Object.create = Create;   // Create is defined a few lines above.

The class method Object.create() is built-in automatically in JavaScript versions later than EcmaScript 3; it is mimicked by the class method in the code snippet above.

In the next example the object heir inherits the property a and the method meth from object literal progen that functions as progenitor for heir:

var progen = {a: 123, 
              meth: function() {println('This method is inherited')}
             };
var heir = Object.create(progen);
println("Inherited property heir.a: " + heir.a)
heir.meth();         // Invoke inherited method

This writes:
Note that progen is an example of a progenitor that is not named prototype.

A progenitor C.prototype can be assigned to obj in two ways:

obj = Object.create(C.prototype) and obj = new C(args). 

By definition, they have in common that all members of C.prototype are inherited by obj. They differ in the fact that during the operation new C(args) the body of the constructor C(args) is executed, while C(args) is not executed during the invocation of Object.create. In the special case that the constructor C() has an empty body, there is no difference.

To contents

Prototype chains

All objects, except one, have a progenitor. Object literals have Object.prototype; object objects usually have C.prototype, a member of their constructor C(); functions have Function.prototype; arrays have Array.prototype. The only object without a prototype is Object.prototype.

If upon read access, a key is not found among the own members of the object, a hidden pointer is followed to the object's progenitor and the key is sought among the keys of the progenitor. See, e.g., an illustration where the progenitor is the prototype member of the constructor. The hidden pointer may be set by the action of new, or may be set by default. In addition, the pointer can be set by the class method Object.create(p) that creates an object with progenitor p.

When the progenitor inspected does not posses the key to be retrieved, the key is searched higher up in the prototype chain.  [It would be consistent to speak of a "progenitor chain", but this deviates too much from common usage.]   The first progenitor inspected, being an object itself, has also a progenitor, the next progenitor in the prototype chain. If the key sought is not a key of the second member of the prototype chain either, the search proceeds up the chain following hidden pointers from progenitor to progenitor. The search must end at a progenitor that itself does not have a progenitor, which is Object.prototype. All prototype chains terminate at Object.prototype. If the desired key is not found at the top, the value undefined is returned. When the desired key is found below the top, its value is returned and the search along the prototype chain is terminated. All keys higher up than the key returned are masked by the resulting key.

When an invoked method is not an own member of the instance, it is searched higher up in the chain and invoked as soon as it is found: the action is delegated to the higher instance method. It is important to note that the keyword this inside the method obtains the name of the instance that started the search—that delegated the action.

To contents

Examples of prototype chains

Most commonly, a prototype chain consists of only three members, as in:
var C = function() {};
var instance = new C();
instance.key → C.prototype.key → Object.prototype.key      // Prototype chain

A prototype chain can be extended by inserting a constructor into it; this is known as subclassing. A subclass Csub has all inheritable properties of its base class C. Usually a subclass is introduced to get members in addition to those of the base class, the subclass members. Subclassing is performed as in the following very simple example:

var C = function() {};                      // Base class  constructor
C.prototype.base = "Base property";         // Define example base class property  `base`

var Csub = function() {};                   // Subclass constructor
Csub.prototype     = new C();               // The subclassing statement: Csub.prototype is of class C
Csub.prototype.sub = "Subclass property";   // Define example subclass property `sub`

var objBase = new C();                      // Instance of base class C
var objSub  = new Csub();                   // Instance of subclass Csub

println("objBase.base: "  + objBase.base);
println("objBase.sub:  "  + objBase.sub);

println("objSub.sub:   "  + objSub.sub);
println("objSub.base:  "  + objSub.base);

This is the output:

Explanation: The instance objBase is of class C—the base class—and has an inherited property with key base and the value "Base property" that is printed. In the next println statement objBase.sub is accessed, but the key sub is not found, neither as an own property of objBase, nor in its progenitor C.prototype, nor in the built-in master Object.property. Therefore the value undefined is returned and printed.
The subclass constructor Csub(), being a function, obtains the automatic member Csub.prototype. This member is overridden by the subclassing statement:   Csub.prototype = new C();.   The instance objSub is by definition of class Csub. When objSub.sub is accessed, the key sub is sought and found in the lowest progenitor Csub.prototype. Its value: "Subclass property" is returned and printed. When objSub.base is accessed, the key base is not found in its lowest progenitor Csub.prototype, but is found in the progenitor one higher up, in the progenitor of Csub.prototype, which is C.prototype. Its value is "Base property". Hence, the prototype chain for key objSub.base consists of the members:
    objSub.base → Csub.prototype.base → C.prototype.base → Object.prototype.base   // Prototype chain

The next example shows a longer chain (left to right implies lower to higher) that defines the search order of the methods of instance f4 at the bottom of the chain. The following prototype chain will be constructed (the key x is either a, b, c, or d):

f4.x → F3.prototype.x → F2.prototype.x → F1.prototype.x → Object.prototype.x      // Prototype chain

This is done as follows :
var F1 = function() {};
F1.prototype.a =  function() {return  '1 AAA';};
F1.prototype.b =  function() {return  '1 BBB';};
F1.prototype.c =  function() {return  '1 CCC';};
F1.prototype.d =  function() {return  '1 DDD';};

var F2 = function() {};
F2.prototype   = new F1();    // Subclassing statement
F2.prototype.b =  function() {return  '2 BBB';};  
F2.prototype.c =  function() {return  '2 CCC';};  
F2.prototype.d =  function() {return  '2 DDD';};  

var F3 = function() {};
F3.prototype   = new F2();    // Subclassing statement
F3.prototype.c =  function() {return  '3 CCC';};
F3.prototype.d =  function() {return  '3 DDD';};

var f4       = new F3();      // Instance f4 of subclass F3
f4.d         = function() {return  '4 DDD';};   // Assignment

println('f4.a == ' + f4.a() + ' ' + f4.hasOwnProperty("a") );
println('f4.b == ' + f4.b() + ' ' + f4.hasOwnProperty("b") );
println('f4.c == ' + f4.c() + ' ' + f4.hasOwnProperty("c") );
println('f4.d == ' + f4.d() + ' ' + f4.hasOwnProperty("d") );

[Recall that o.hasOwnProperty("p") returns false if p is an inherited member of o and true otherwise.]

The snippet prints:

Notice that the value of the member lowest in the chain is printed, higher members with the same key are masked. For instance, the key d is assigned to four different object methods. The own (non-inherited) and lowest method f4.d is retrieved, executed (returning ['4 DDD') and printed. Similarly, c is assigned three times, the lowest inherited method f4.c()==F3.prototype.c()=='3 CCC' is retrieved, and so on. For the printing of f4.a()=='1 AAA' almost the whole chain had to be searched from bottom to top.

The prototype chain is not inspected when a member is accessed in write mode. Remember, that writing always creates or updates an own member. When a member is updated, lower objects with the same key inherit the updated value. In fact, this was illustrated already in the previous example when F2.prototype.b was assigned. The earlier binding of key b to F1.prototype was overridden and replaced by a binding to F2.prototype. We verify this:

println(F2.prototype.b() + " " + F2.prototype.hasOwnProperty("b"));

prints:

Note finally that the prototype chains in the examples above start with the key of an object object. For the keys of other objects, such as functions or arrays, a different rule applies, as will be seen for functions in this chapter.

To contents

this in inherited methods

In chapter 7 the value of the keyword this was discussed in different contexts, among them object methods and constructor functions. For object methods it is irrelevant whether the method is own or inherited. In both cases this is a pseudonym for the object.

In the following example the object obj of class Fsub gets two methods: (i) inheritedMethod, inherited from Fsub, and (ii) ownMethod, an own method set during execution of new Fsub(). Both methods of obj contain this that will be shown to be a pseudonym for obj.

var F = function() {
   this.inheritedMethod = function(){this.a = 'Inherited'};
}
var Fsub = function() {
    this.ownMethod = function(){this.b = 'Own'};
}

Fsub.prototype = new F();     // Subclassing statement sets  `Fsub.prototype.inheritedMethod`
var obj        = new Fsub();  // sets  `ownMethod` (own) and `inheritedMethod` (inherited) 

// Verify the types of the methods:
println('obj.inheritedMethod is owned by obj? ' + obj.hasOwnProperty('inheritedMethod'));
println('obj.ownMethod is owned by obj? '       + obj.hasOwnProperty('ownMethod'));

// Invoke the methods
obj.inheritedMethod();                // Invokes inherited method, sets obj.a
obj.ownMethod();                      // Invokes own method, sets obj.b

println('obj.a == ' + obj.a);
println('obj.b == ' + obj.b);

prints:

To contents

Example of subclassing

The way that JavaScript handles subclassing was touched upon in section 8.1. It was shown that by application of the operator new the prototype of a subclass constructor is made to point to the prototype of a class constructor higher in the prototype chain. This has the consequence that instances of the subclass inherit from their ancestor class. In this subsection a more complicated example of subclassing is given. It is based on a code snippet taken from JSfiddle.

Suppose that a parent class Super exists and that the own and inherited members of this class match almost perfectly the members of a child class Child. Only a few minor modifications are required to make Child complete. Maybe the addition of an extra method, or a modification of an existing method is needed. (In the example below the method getX of Super is replaced in Child). A constructor Child() can be defined that in its body executes the constructor Super(). By this execution Child() creates the same own members as those of Super. Furthermore, Child is subclassed to Super by insertion of Child.prototype in the prototype chain below Super.prototype, so that the instances of class Child inherit all the members of class Super. The subclass Child has at this point the very same properties and methods—own and inherited—as Super. Once the class Child has been established, the required changes and additions can be made to it; they do not affect the parent Super at all.


var Super = function(arg) {
    /*  Constructor function for parent class Super. */
    
    // Set `x` and `prop`,  own properties of instances of class Super:
    this.x    = arg;
    this.prop = 'Prop in Super';
}

Super.prototype = {
    // `getX` and `get10X` are methods inherited by instances of class `Super`.  
        
    getX:  function() { 
               println(this.x); 
           },
    get10X: function() {
              println(this.x * 10);
            }   
}       
          
var Child = function(arg) {
    /*  Constructor function for class Child. */
    
    Super.call(this, arg);       // Execute `Super` as method of `this`.
       
    // ( The statement `child = new Child(..)` below will invoke `Super` with `this` 
    //   equal to `child`. Execution of `Super` sets own properties: `child.x` 
    //   and `child.prop` )      
}
      
// Create `Child.prototype` with progenitor `Super.prototype` (subclassing).
// We do not want to execute `Super()` yet,  so we use `Object.create`, rather 
// than `new Super()`, as  subclassing statement:
Child.prototype = Object.create(Super.prototype);   

Child.prototype.getX = function() {
    /*  Function overrides the method `getX` of class Super. */
    println(this.x * 2);
}

// In the next statement  Child() is executed with `this` equal to `child`; 
// `Super()` is invoked during execution:
var child = new Child(5);   // Create instance of class Child 

// Note that the own properties `child.prop` and `child.x` are set 
// during execution of Child(). 
println('child.prop: ' + child.prop);
println('child.x: ' + child.x);

// The inherited method `child.get10X()` is set by the subclassing statement 
// `Object.create(..)`.  Invoke it:
child.get10X();    // prints 50

// Confirm heritage statuses:
println('prop   own property of child? ' + child.hasOwnProperty('prop'));
println('getX   own property of child? ' + child.hasOwnProperty('getX'));
println('get10X own property of child? ' + child.hasOwnProperty('get10X'));

// Invoke overridden method:
child.getX();     // prints 10

The snippet prints:

The "bare bones" version of the above code snippet—without prints and comments—is clearer for those who understand its logic:
var Super = function(arg) {
    this.x    = arg;
    this.prop = 'Prop in Super';
}
Super.prototype = {
    getX:  function() { 
               println(this.x); 
           },
    get10X: function() {
               println(this.x * 10);
            }   
}       
var Child = function(arg) {
    Super.call(this, arg);       
}
Child.prototype = Object.create(Super.prototype);   
Child.prototype.getX = function() {
    println(this.x * 2);
}
var child = new Child(5);   
child.get10X();    
child.getX(); 

To contents

Inheritance of functions from Function.prototype

The following rule was mentioned in passing: JavaScript has a built-in constructor for functions named Function(). One can, for example, define a function as follows:
var f = new Function('x', 'return x*x;');
println(f(3.0));

which prints

The constructor Function(), being a function, has the member prototype. The function definition via new clearly sets out that the function f—seen as object—inherits from Function.prototype. For instance, the methods call() and apply(), introduced earlier, are members of Function.prototype.

The definition of a function by application of new to Function(..) is completely equivalent to the more compact form:
var f = function(x) {return x*x;};
println(f(3.0));

which prints

The function f defined in this—more common—way also has Function() as its constructor.

Function.prototype, being an object, has as ultimate progenitor Object.prototype. Functions inherit first from Function.prototype and after that from Object.prototype. The shortest [below it will shown to be the only] prototype chain associated with a function object f() is:

        f.key → Function.prototype.key → Object.prototype.key      // Prototype chain

In the next example it is exhibited that this prototype chain for functions is not much different from the one for other objects. The masking of keys is exactly the same.
var f = function f {};
f.a    = 'A';
Function.prototype.a = 'AA';
Function.prototype.b = 'BB';

Object.prototype.a   = 'AAA';
Object.prototype.b   = 'BBB';
Object.prototype.c   = 'CCC';

println('f.a         == ' + f.a);
println('f.b         == ' + f.b);
println('f.c         == ' + f.c);
println('f.d         == ' + f.d);

prints:

The following example shows that a member of an object is searched for in Function.prototype if and only if the object is a function.

Object.prototype.key   = "Inherited from Object"
Function.prototype.key = "Inherited from Function";

var o = function() {};        // function
var p = [];                   // array
var q = {};                   // object literal
q.f   = function() {};        // method (a function)
var s = new String('XYZ');    // string object
println("o.key == " + o.key);
println("o.prototype.key == " + o.prototype.key);
println("p.key == " + p.key);
println("q.key == " + q.key);
println("q.f.key == " + q.f.key);
println("s.key == " + s.key);

prints:

Since Object() and Function() are both functions, their properties are also searched among the properties of Function.prototype that masks Object.prototype. Example,

Object.prototype.k = 'Object k';
Object.prototype.l = 'Object l';
Function.prototype.k = 'Function';
println('Function.k == ' + Function.k);
println('Function.l == ' + Function.l);
println('Object.k == ' + Object.k);
println('Object.l == ' + Object.l);

prints:

Hence, via a detour along Function.prototype, the object Object inherits from Object.prototype.

It was shown earlier that a prototype chain starting with an object object could become part of a prototype chain of arbitrary length by repeated subclassing. Now the question arises: can a function be the start of a prototype chain of arbitrary length? Or stated equivalently, can the class Function be subclassed? The answer is no. The different ways of constructing a function all use Function() as constructor. It is not possible to use another function constructor. In contrast to object objects, where any function can act as a constructor, JavaScript knows only one function constructor. Also arrays, object literals, numbers, regular expressions, dates, booleans, and string objects have one constructor only, namely the respective built-in functions: Array(), Object(), Number(), RegExp(), Date(), Boolean(), and String().

The object Function.prototype has automatically the methods call(), apply(), bind(), and toString(). Sometimes it may be useful, since subclassing of functions is not possible, to define Function.prototype.newMethod(); newMethod() is then accessible by any function or method.

To contents

Example of a Factory Function

We saw earlier that inheritance from any object is possible by application of the class method Object.create(). This method is used in "factory functions"—by definition functions that return an object. The object returned from a factory function inherits from an object that acts as a progenitor. Remember that the statement
   var child = Object.create(base);

binds the members (keys and their values) of base to the newly created object child. The object base is the progenitor of child, the methods and properties of base are inherited by child. If child is preexisting, it is overridden. The objects base and child are associated in the asymmetric one-way manner that is typical for inheritance. That is, when a member of base is modified or a member is added, the object child follows these changes. Conversely, changes in child do not affect base, but create own members of child.

We know turn to an example of a factory function, which, as stated, returns an object. An array object points is constructed consisting of a pair of points on the real line; the array is produced by the function makePoints. Two methods will be defined. First, between(x) that returns true if x lies between the two points. And secondly, distance that gives the distance between the points. The methods will be members of the progenitor object. Not only can the progenitor be named anything, it can be "parked" everywhere. It makes sense to park it as a member of the factory function itself and name it "methods", because it is an object with two methods: between and distance.

function makePoints(p1, p2) {        // factory function
     var points = Object.create(makePoints.methods);
     points[1] = p1;
     points[2] = p2;
     return points;                  // pair of points, an array object
};

// Progenitor object containing methods for points, property of function makePoints:
makePoints.methods = {
    between: function(x) {
                if (this[1] <= this[2]) {
                      return (this[1] <=  x &&  x <= this[2])   
                }
                else {
                      return (this[2] <=  x &&  x <= this[1]);  
                }
             },

    distance: function() {
                 return Math.abs(this[1] - this[2]);
              }
}

// Invoke the factory function:
var points = makePoints(3, -1);
println('Points: ' + points[1] + ', ' + points[2]);

// Use its methods
println('0 in interval? ' + points.between(0));
println('3.1 in interval? ' + points.between(3.1));
println('-5.0 in interval? ' + points.between(-5.0));
println('distance: ' + points.distance(4));

The output of the example is:

To contents

Summary

The JavaScript entities of type string, number, boolean, null, and undefined are primitive and immutable. All other JavaScript entities are objects. An object is a collection of keys bound to separate JavaScript entities, their values. A key-value pair is a member of the object. Keys may appear in refinements, as in: object.key. All JavaScript variable names are keys of well-defined objects, even when the object is not shown explicitly. Global variables are keys of the global object that in web pages has the name window.

The binding of a key to an object can be either a one-way or a two-way binding.

One-way binding is also referred to as inheritance. The binding can be achieved in two ways:

      var heir = new Constructor();
      var heir = Object.create(Constructor.prototype);

By execution of these statements heir is created and its keys and values are the same as those of the progenitor Constructor.prototype. These inherited members of heir are bound to equally named members of the progenitor, but the converse is not true. Changes in the properties of Constructor.prototype affect dynamically (at run-time) the inherited properties of heir. Changes of inherited properties of heir do not affect the properties of progenitor. An object may have non-inherited—so-called own—properties. An inherited property becomes an own property when its key is reassigned to any value in an assignment statement.

Two-way binding is by direct assignment:

      var objectA = objectB;

After this statement all keys and values are shared between the two objects. The one object is an alias or pseudonym of the other. The names objectA and objectB may be refinements. For instance, objectA could be of the form grandParent.parent.child.

A JavaScript function can be invoked as in most languages; it causes execution of the statements in the function body. In addition, a JavaScript function is an object with keys and their values. The most important member of a constructor function is prototype.

To contents

Paul E.S. Wormer, March 2011