© 2019 Meouzer Consortium

A Review of Inheritance in JavaScript

Meouzer Meouzer the Snarky Cat Programming Cat meouzer@gmail.com
loading
C++ hsas only one wase! It rgiht wise!! JavaScript countless waises, and all's wrung!!!.
Meouzer

About the Author

As an adept JavaScript master, Meouzer thoroughly enjoys writing his own articles, and I am grateful for the opportunity of employing my skills in correction of the atrocious grammar that cats think they can get away with. Meouzer's spelling is natively quite good, but since cats write articles with keyboards, it's understandable that misspellings are the catographical results. Actually, and this is quite embarrassing, Meouzer was an excellent typist until we had him declawed. For some unfathomable reason the vet didn't disclose the adverse effects of declawing on a cat's ability to accurately strike keys. This was just like the time Meouzer was taken in for rambunctiousness and somehow ended up getting neutered. After some protest, the fee was waived, which was a great deal since we were going to have him neutered anyway.

Glossary and Fun Facts

The glossary is in logical rather than alphabetical order.

Primitive

A JavaScript element is a primitive if it has permanently has no properties of its own. By permanent we mean that the element has no properties at definition, and properties can never be added to the element after its definition.

Explicitly the primitives are the, undefineds, nulls, booleans, numbers, strings, symbols, and bigints. A test for being a primitive is that typeof(x) is either "undefined", "null", "boolean", "number", "string", "symbol", or "bigint".

Object
An object is an element that is not a primitive.
Direct Definition of Property

For an object x, a property p may be directly defined through an assignment statement such as x.p = ... or through a property descriptor used in one of the following manners.

// First manner. Create property p at creation of x var x = Object.create(y, { p: // define property p of x { // This object is a property descriptor }, ...; }); // Second manner. Define the property and other properties together. Object.DefineProperties(x, { p: // define property p of x { // This object is a property descriptor }, ...; }); // Third manner. Define just the property and no others Object.defineProperty(x, "p", property-descriptor-here);
Internal Prototype

The internal prototype of any element x is Object.getPrototypeOf(x). Every JavaScript element except for the undefineds and nulls has a internal prototype. For an element x, if x.__proto__ is defined then it is the internal prototype. However the proto property is not defined for null objects.

The internal prototype of booleans, numbers, and strings is obtained by boxing: such a primitive x really doesn't have an internal prototype but when Object.getPrototypeOf(x) is called, JavaScript behind the scenes converts x to an object and then takes the internal prototype: booleans are converted to Booleans, numbers are converted to Numbers, and strings are converted to Strings: Only after this conversion is Object.getPrototypeOf() called. So technically, booleans, numbers, and strings don't have internal prototypes.

Boxing
Boxing is when JavaScript automatically replaces booleans, numbers, or strings with Booleans, Numbers, or Strings before an operation on the element is executed. We have an example above, but usually boxing is used in connection with evaluating properties. For example, if String.prototype defines a property p, then "cat".p is first evaluated by turning "cat" into aString = new String("cat"). Then aString.p is determined and gives the value of "cat".p.
Top Level Object

Any object x whose internal prototype is null. Equivalently an object that doesn't inherit from another object.

Object.prototype is the most famous top level object. All the other top level objects take the form Object.create(null, ...). These are called top level null objects. See Null object.

Inheritance Chain or Prototype Chain

For an element x, neither undefined nor null, its inheritance or prototype sequence/chain starts with x. Given a member of the sequence the next member is its internal prototype. The sequence continues until a top level object is reached, which is the last member of the sequence or chain.

We say that x inherits from the other members y of the inheritance chain of x, because x inherits their properties (see Inherited Property).

Degree of Inheritance
The degree of the inheritance of x from y is the number of times you have to take the internal prototype starting with x to reach y.
Direct Inheritance
An inheritance of degree one is direct. In other words if the internal prototype of x is y then x directly inherits from y.
Inherited Property
Let x be an object. If x defines a property p directly then x does not inherit the property p.

If x does not define p property directly, then look up the inheritance chain to find the first member y that defines the property p directly. The fun filled fact is that x.p is defined to be y.p and we say x inherits the property p from y. If there is no such member y in the inheritance chain of x that directly defines the property p then x.p is not defined and x.p === undefined evaluates to true.

Derivation
Derivation is basically synonymous with inheritance. For example if x inherits from y, we can say x is derived from y. Furthermore, if x inherits a property p from y, then we can say x derives the property p from y. Moreover, if x directly inherits from y, we can say x directly derives from y. OK! You got the idea.
Null Object
Any object, which is neither Object.prototype nor inherits from Object.prototype.

You should be able to figure out why an element created from or inherited from a null object is a null object.

Standard object
Object.prototype or any object which inherits from it.

When most think of an object, it's of a standard object because most don't know about null objects.

Null Class
A class whose prototype is a null object. It's a fact that class instances of a null class are null objects.
Object Creation
The following code shows how to create a new object x from an existing object y.
// Create new object x from existing object y var x = Object.create(y) { // properties and their property descriptors here }); // JavaScript insures that x directly derives from y, // and so x inherits the properties of y unless x // defines them directly.
Instances

By definition, an element x is an instance of a class/constructor foo precisely when foo.prototype is in the inheritance chain of x, i.e., x derives from foo.prototype directly or indirectly. Actually, this definition holds for any function foo being a constructor or not.

A test for instances is that x instanceof foo evaluates to true precisely when x is an instance of foo. Except the test doesn't work for the BigInt, and Symbol functions. See appendix Are BigInt and Symbol Classes?

For example "cat" instanceof String evaluates to false, which correctly states that "cat" is not an instance of String. In this situation JavaScript will not box the string "cat" to a String. As noted before, technically "cat" has no inheritance chain and so can't inherit from String.prototype.

Class Instances
If foo is a class/constructor then an element of the form x = new foo(..) is a class instance of foo.

It's a fact that class instances of foo are instances of foo but the converse does not hold because there are instances, for example like Object.create(foo.prototype), which are instances but not class instances.

Synonyms for Inheritance

It's strange that there are so many synonyms for the type of derivation and inheritance described above. Multiple committees, not run by cats, were obviously at work. Inheritance/derivation synonyms follow.

  1. object inheritance/object derivation
  2. proto inheritance/proto derivation
  3. prototypical inheritance/prototypical derivation
  4. prototypal inheritance/prototypal derivation
  5. prototype inheritance/prototype derivation

The author has seen all five of these used. If you want your listeners to not understand you at all, use prototypal.

Partition of Elements by Inheritance

Partition of Elements by Inheritance
Elements with no inheritance chain undefineds
nulls
Elements with an inheritance chain Null Objects is neither Object.prototype nor derives from it
is or derives from Object.prototype Primitives boolean
number
string
symbol
BitInt
Standard Objects

Testing Inheritance

If x and y are objects, how do you tell if y is in the inheritance chain of x? All you have to do is ask y. y.isPrototypeOf(x) is true precisely when y is in the inheritance chain of x.

On a related note, if x is an object and foo is a constructor then x instanceof foo is true precisely when foo.prototype is in the inheritance chain of x.

Inheritance Chains of Primitives

The primitives with an inheritance chain via boxing are boolean, number, and string. The primitives with an inheritance chain are symbol and bigint.

The inheritance chain of the number 7 follows.

  1. Object.getPrototypeOf(7) = Number.prototype
  2. Object.getPrototypeOf(Number.prototype) = Object.prototype

Now we are most interested in Number.prototype from which 7 directly derives. We will add a property to Number.prototype and show it is inherited by 7.

Example: numbers are members of the Number class.
// Add a property called message to Number.prototype Object.defineProperty(Number.prototype, 'message', { value:function() { alert("Hello! I'm Mr. Number number " + this + "!!"); } }); // And yes the property is immediately available to the number 7 (7).message(); // Hello! I'm Mr. Number number 7!!

Analogous discussions hold for booleans/Booleans and strings/Strings. See the Boxing appendix for more information.

Objects, Standard and Null

Test for Objects

By consensus all elements except for the primitives are objects. The primitives are the, undefineds, nulls, booleans, numbers, strings, symbols, and bigints. That is the elements x whose typeof(x) is either "undefined", "null", "boolean", "number", "string", "symbol", or "bigint". A defining characteristic of primitives is that properties can't be added to them. Its's also true that they do not have any properties of their own.

In JavaScript, functions are first-class objects, because they can have properties and methods just like any other object. What distinguishes them from other objects is that functions can be called. In brief, they are Function objects.
  MDN
Data Types Recognized by the typeof Operator
Primitive Data TypeCategorizationTest x for Membership
nullThe literal null or variable set to suchx === null
undefinedThe literal undefined or variable set to such typeof(x) == "undefined"
booleanThe literals true, false or variable set to such typeof(x) == "boolean"
numberA literal number or variable set to suchtypeof(x) == "number"
stringA literal string or variable set to suchtypeof(x) == "string"
BigIntA literal BigInt or variable set to such.
Or a class instance of BigInt
typeof(x) == "bigint"
SymbolA class instance of Symboltypeof(x) == "symbol"
Classless Data TypeCategorizationTest x for Membership
functionA functiontypeof(x) == "function"
objectAn objecttypeof(x) == "function" ||
typeof(x) == "object"

From the typeof table we have the following test.

function isObject(x) { return (x != null &&  typeof(x) == 'object') || typeof(x) == 'function'; }

No one considers null to be an object but unfortunately typeof(null) evaluates to "object" most likely by a bad original decision.

Now x instanceof Object being true is NOT a test for being an object because of the existence of null objects. Also because Object.prototype is an object yet Object.prototype instanceof Object evaluates to false.

As we shall see x instanceof Object evaluates to true precisely when x is a standard object not equal to Object.prototype.

Test for Standard Objects

function isStandardObject(x) { return x === Object.prototype || Object.prototype.isPrototypeOf(x); // this says x is either Object.prototype or else derives from it }

Two Tests for Null Objects

function isNullObject(x) { return x !== Object.prototype && Object.prototype.isPrototypeOf(x); // this says x is neither Object.prototype nor derives from it } function isNullObject(x) { return x.__proto__ === undefined; }

Why is the second test definitive? Because by a quirk of JavaScript, a null object starts out with an undefined proto property. If you try to change the proto property it doesn't stick: the proto property remains undefined. If you take a standard object and try to set its proto property to undefined it doesn't stick: the proto property remains the same.

General use of the x.__proto__ property is deprecated. Use Object.GetPrototypeOf(x) instead. JavaScript simply screwed up because x.__proto__ is supposed to be the internal prototype of an object x but this fails for null objects.

Checking for Properties

If you want to know if x or an ancestor defines a property a, just check the expression x.a  !==  undefined. It's true precisely when x or an ancestor has defined the property a. Be careful to use two equality symbols because of JavaScript shenanigans where statements like undefined != null evaluate to false.

If you want to know if x specifies the property a directly, check hasOwnProperty(x,a), which will be true precisely when x directly specifies the property a.

function hasOwnProperty(x,a) { return Object.prototype.hasOwnProperty.call(x, a); }

You may be curious has to why we didn't use return x.hasOwnProperty(a). Well this works if x is a standard object, but not if x is a null object because null objects don't inherit hasOwnProperty() from Object.Prototype.

The Null Objects

The only top level null objects take the following form where they are created directly from null.

Object.create(null, { // property descriptors here });

Any object created directly from null is a top-level null object. Any object created directly from a null object is a null object. A class foo is a null class if its prototype foo.prototype is a null object. So a class deriving from a null class is a null class. Instances of null classes are null objects. That covers how all null objects are created.

Normally the internal prototype Object.getPrototypeOf(x) of an element is its x.__proto__ property. However, one characterization of null objects is that their __proto__ property is undefined.

Constructing Null Objects
(Derivations of top level null objects through Object.create())
function getTopLevelParent(x) { if(x === null || x === undefined){return undefined;} for(var P = x; Object.getPrototypeOf(P) !== null; P = Object.getPrototypeOf(P)); return P; } // Create a top level null object. \^i1var x = Object.create(null, { cat:{value:'meouzer'}, food:{value:'tuna'}, });\$i1 // Verify x is a null object. \^i1alert(getTopLevelPrototypeOf(x) !== Object.prototype);\$i1 // Verify again that x is a null object. \^i1alert(x.__proto__ === undefined);\$i1 // Verify that x is a top level object. \^i1alert(Object.getPrototypeOf(x) === null);\$i1 // To construct other null objects, continue the // derivation process with Object.create(). \^i1var y = Object.create(x, { type:{value:'rambunctious'} });\$i1 // Verify y is a null object \^i1alert(y.__proto__ === undefined);\$i1 // Verify again that y is a null object. \^i1alert(getTopLevelPrototypeOf(y) !== Object.prototype);\$i1 // Verify that y inherits the properties of x with their values. \^i1alert(y.cat == "meouzer"); alert(y.food == "tuna");\$i1

Class Inheritance

A class foo has a constructor of the same name. JavaScript always insures that an instance x of foo created by a call to foo with operator new has internal prototype foo.prototype.

To say that foo derives from a class bar is to say the internal prototype of foo.prototype is bar.prototype. To say that foo derives from an object obj is to say the internal prototype of foo.prototype is obj.

One way to derive the foo class from the foo1 class is to use the following code. However, see section Historical Note on Class Inheritance.

foo.prototype = Object.create(foo1.prototype, { // property descriptors here }); // Since foo.protoype is created from foo1.prototype, the // internal prototype of foo.prototype must be foo1.prototype

Now let's say foo derives from foo1, foo1 derives from foo2, and the derivations continue until foolast which is not created from any other class or element. Then an instance x of foo has the following inheritance chain.

This means the instance of x of foo inherits all the properties of the foo prototypes and Object.prototype.

Now, if foolast were created directly from null as in

foolast = Object.create(null, { // property descriptors here });

then he inheritance chain of x is the following (excluding null)

This means the instance of foo inherits the properties of all the foo prototypes but doesn't inherit from Object.prototype. foolast.prototype is a top level null object. You may want this if you desire to eliminate the inheritance baggage from Object.prototype.

Since Object.prototype doesn't sit atop the inheritance chain, then by our definition of null object, the whole chain from x to foolast.prototype are in fact null objects.

We say that foo to foolast are null classes, which is appropriate because their prototypes are null objects, and all their instances are null objects.

In the first type of derivation, the prototypes of constructors are always given a constructor property set up by JavaScript itself. However, for null classes JavaScript fails to do its duty and there is never a constructor to be found.

Review

Recall that by definition, class inheritance of foo from bar means object inheritance of foo.protoype from bar.prototype.

If you follow the arrows around you can see that x, an instance of foo, inherits from foo.prototype, from bar.prototype, and from foobar.prototype.

It's common and very incorrect to hear that JavaScipt is classless. Constructors/classes are first class JavaScript citizens whose job is to build objects, and bind private variables and public methods. A class, is identified with a constructor and refers to all objects (class instances) created by the constructor. Since class inheritance of foo from bar is defined as object inheritance of foo.protoype from bar.prototype, a great leap is taken and you will hear from various author's that JavaScript is a classless language, but again this is incorrect.

Appendices

The Writable Property Descriptor is "Inherited"

We assume the reader knows all about property descriptors, perhaps from MDN (Mozilla Developer Network). The object P = Object.getOwnPropertyDescriptor(x, "prop") is the property descriptor of the property prop for the object x. The property descriptor has a writable property, which is true precisely when the corresponding property of x may be assigned a (new) value through an assignment statement as in x.prop = 7.

If x.prop is defined with a property descriptor, the default value for writable is false, and if writable is false then statements like x.prop = 7 have no effect. Now you may be suprised by the fact that if y derives from x then statements like y.prop = 7 also have no effect: In other words the writability of the property was inherited from x to y. More simply, you could say the writability of the property of y was derived from x.

Inheriting Writable
const x = Object.create(Object.prototype, { cat: { value:"Meouzer" // The writable property of cat is not specified // and is therefore false by default. } }); const y= Object.create(x, { //cat: //{ // value:"Pete" //} }); y.cat = "Pete"; // No effect. As if non writable were inherited. alert(y.cat); // Meouzer // You can still redefine y.cat, but just not through assignment. // Uncomment the lines just after line 4, comment out line 5, // and you get the expected redefinition: Line 6 will alert "Pete."

Since you know all about property descriptors, the above example with comments shows that the configurable property descriptor is not inherited.

Casting

The statement Object.setPrototypeOf(x, y) resets the internal prototype of x to y. The author calls this a cast of x to y. The cast changes the object from which x directly inherits and so changes the entire inheritance chain of x. However, the cast will result in a broken object if x doesn't support the methods in its new inheritance chain.

Let's suppose that an object x inherits from an object y.

  1. The statement Object.setPrototypeOf(x, y) is an upward cast of x to y.
  2. The equation Object.setPrototypeOf(y, x) is a downward cast of y to x.
  3. If neither x nor z lie in the inheritance chain of the other then the statement Object.setPrototypeOf(x,z) is a sidewise cast of x to z.

An upward cast is the most likely to succeed by not resulting in a broken object. A downward cast is the next most likely to succeed, and a sidewise cast is the least likely to succeed.

If you ever decide to cast, be careful and test. The author has seen a cast object whose inherited properties run 20 to over 100 times slower than normal.

In any particular sitiuation this may or may not make sense. However, you can cast standard objects to null objects, you can cast null objects to standard objects.

Boxing

The primitive types with an "inheritance" chain via boxing are boolean, number, string, while binints andsymbols have actual inheritance chains.

Primitive-Chains.svg
Object.defineProperty(Boolean.prototype, "getMyTypeOf", { value:function() { return typeof(this); } }); var b = true; alert(typeof(b)); // "boolean" alert(b.getMyTypeOf()); // "object"

What this code says is that when you apply an inherited property to a boolean, the boolean is first boxed behind the scenes to obtain a Boolean and then the property is applied to that Boolean, which is why we get "object" and not "boolean" as the result of getMyTypeOf().

For another boxing example, see the next section.

A Note on Class Prototypes

Let's look at an example where we create a property for Klass.prototype. We of course want to use this property on class instances of Klass. We want use the property on Klass.prototype itself (though 99.9999% of the time you don't) and we want to use the property of instances of Klass that are not class instances of class (though 99.9999% of the time you don't want to do this either).

Let's say you want to prototype copy functions for all the built in classes, and objects in general.

A copy function for class instances of Boolean
Object.defineProperty(Boolean.prototype, 'copy', { value:function() { if(typeof(this) == "boolean") return this; // Failed attempt to avoid boxing if(isBoolean(this)) return new Boolean(this.valueOf()); // for class instance of Boolean if(this === Boolean.prototype) return this; // for the prototype return Object.create(Object.getPrototypeOf(this)); // for other instances of Boolean } }); // First the attempt to avoid boxing is impossible. As soon as true.copy() is called // true is boxed as new Boolean(true), and so line 3 does not get executed. Line 4 // gets executed instead. If x = new Boolean(true), then the call x.copy() // executes line 4 and a copy is made. For the prototype something that // makes sense is returned on line 5. For the other instances of Boolean something // that makes sense is returned on line 6, but in general there may be nothing to // write that makes sense. // In general, class prototype properties could be written as follows. The theme is // that if an object can't use a property, the property should be set to undefined for // that object. Object.defineProperty(Boolean.prototype, 'property', { value:function() { if(isBoolean(this)) return "something"; // for class instance of Boolean return undefined; // For Boolean.Prototype and remaining instances of Boolean } }); // or Object.defineProperty(foo.prototype, 'property', { value:function() { if (Object.getPrototypeOf(this) === foo.prototype) { return "something"; // for class instances of foo } return undefined; // For foo.Prototype and remaining instances of foo } });

Historical Note on Class Inheritance

Everyone now knows that to derive a class foo from bar one can create foo.prototype with Object.create() with first parameter bar.prototype. As in

foo.prototype = Object.create(bar.prototype, { // Property Descriptors for foo.prototype here. });

However, there was a time when there was no Object.create() and no __proto__ exposed for manipulation. So what did programmers do? It seems a lot of smart programmers did a silly thing because JavaScript did not expose a good way of deriving. The capability of useful derivation was always there, but JavaScript did not make it available. The correct way was very obscure.

Douglass Crockford wrote about this obscure technique at http://crockford.com/javascript/prototypal.html, but I don't think anyone caught on. I found this technique on my own, which is why I recognized it while reading Crockford. My version is protoProxy.

protoProxy = function(myClass) { function foobar(){}; foobar.prototype = myClass.prototype; return new foobar(); } // Now to derive the class foo from bar, write one short line. foo.prototype = protoProxy(bar);

So protoProxy was the historical substitute for Object.create() and completely equivalent to it. Now what was the silly thing that programmers did, me included? Instead of line 5, one would write the following.

foo.prototype = new bar(...);

Nowadays, you don't have to think hard on why this is bad, unless you really want to derive from an instance, but everyone did it way back.

What protoProxy does is to insure that the internal prototype of foo.prototype is bar.prototype, which means that foo derives from bar. This is just protopalriffic.

Top of the Inheritance Chain

function getLastPrototypeOf(x) { if(x === null || x === undefined){return undefined;} for(var P = x; Object.getPrototypeOf(P) !== null; P = Object.getPrototypeOf(P)); return P; }

getLastPrototypeOf(x) is the top-level element from which x inherits.

The most distinguished top-level element is Object.prototype. There are infinitely many possible top level null objects every one of which is created from null as follows.

var myTopLevelNullObject = Object.create(null, { //property descriptors here });

Are BigInt and Symbol Classes?

BigInt is a function that, creates an element, enforces a contract on it, and sets its prototype to BigInt.prototype. But that's exactly the job of a constructor and so BigInt perfectly mimics a constructor even though new isn't used. The same discussion holds for Symbol.

Let x = BigInt(7). It's a fact that the internal prototype of x, Object.getPrototypeOf(x), is BigInt.prototype.

The case against being classes is that both x instanceof BigInt and BigInt.prototype.isPrototypeOf(x) evaluate to false. However, these two are obvious JavaScript screw ups because both say that x can't inherit from BigInt.prototype, but this contradicts the fact that it does inherit from BigInt.prototype because the internal prototype of x is BigInt.prototype.

The author suspects that behind the scenes, a bigint is a object masquerading as a primitive. This is because x.__proto__ = BigInt.prototype. So a bigint has a proto property and is hence an object by our definition of object. You might say x.__proto__ === BigInt.prototype is true only by boxing, but what would x be boxed to? There is no answer! Maybe our definition of object should be changed.

From the Meouzer Collection

Well I hate to confess
but doing JavaScript is a stress
so Meouzer got to working
and after he quit smirking
turned my JavaScript into a real mess