Click here to Skip to main content
15,881,852 members
Articles / Programming Languages / Javascript

Father Prototype and Mother Constructor

Rate me:
Please Sign up or sign in to vote.
5.00/5 (4 votes)
2 Jan 2020GPL319 min read 8K   5   2
Solid JavaScript from facts to rules

Introduction

"UML is probably responsible for the destruction of object-oriented programming. Because its total focus on classes and not on objects has corrupted an entire generation of programmers." - Dave Thomas

"The idea was 'Come and do Scheme in Netscape. Put this programming language into the browser.'" - Brendan Eich

Most people get acquainted with JavaScript like "well, it's an object oriented, dynamically typed, programming language", at least I was. Learning more and more of it, became obvious that the strength of the language lies mostly on its powerful functions. On its first-class functions.

Prototypes are one of the most fundamental JavaScript features. If I start this article with objects, there will be trouble, if I start with functions, there will be double. Either way, I'll soon get into the "Chicken-and-egg" situation.

I'll write some examples and point to some facts. Let's discover the rules of the prototype and build upon the constructors. Something tells me it's best to start, like everybody was starting with this language. You create an object... like this:

Example 1

JavaScript
var myCar = {
    color: "silver",
    weight: 940
};

But, what's an object? More general on that at Appendix C. For JavaScript, "objects represent collection of named values. The named values, in JavaScript objects, are called properties. Object properties can be both primitive values, other objects, and functions. An object method is an object property containing a function definition." - w3schools

In JavaScript, variables and properties fall into two categories: primitive and reference types. The language has evolved rapidly this last couple of years, so I want to be specific, even punctual. This text will confirm to the ES5.1 standard of June 2011, no more, no less. Five shalt be the number thou shalt count and the number of the counting shalt be five.

Primitive and Reference Types

There are five primitive types: number, string, boolean, null and undefined. This types are passed to functions and operators by value. Passing by value is when you pass a copy of the variable contents to an operator or a function.

Example 2

JavaScript
var text1 = "bird";
var text2 = "bird";

text1 == text2    //true

This means text1 and text2 have the same value, compared letter by letter, although they exist physically distinctive in the computer memory. There are two "bird"s.

A more helpful explanation is, JavaScript "tracks variables for a particular scope with a variable object. Primitive values are stored directly on the variable object". - The Principles of Object-Oriented JavaScript

A variable object is a special object related with an execution context which stores: variables, function declarations and function formal parameters declared in that context.

This two variables are in the global scope and the variable object for the global scope is the global object. Luckily, when we are in the browser console, we can log the global object simply by typing its name, window. You will get all the properties of window and if you defined text1 and text2 as "bird", you will see the two of them. Same value, different slot in the global object.

If you pass text1 as a function argument, you will get the contents of text1 copied and slapped into the new variable object of the called function scope. This time by its new name as it was declared in the function's parameter list. In this example as x.

Example 3

JavaScript
function test(x) {
    return x;
}

Unfortunately, we cannot see the variable object of a function. It's an implementation detail. While the global variable object has a defined name for us as window, the variable object inside a function scope has no specific name, handle or identifier.

One more thing, primitive values are immutable and that's it. You can't change it no more, but you can reassign a new primitive value to your variable.

References

All reference data types in JavaScript represent objects. Some of them we know as arrays, others as functions, as regular expressions... "Reference values are placed as a pointer in the variable object, which serves as a reference to a location in memory where the object is stored." - The Principles of Object-Oriented JavaScript

Example 4

JavaScript
var object1 = {
    text: "paragraph"
    };
var object2 = {
    text: "paragraph"
    };

object1 == object2                //false
object1.text == object2.text      //true

Though object2 is a verbatim copy of object1, they are not considered as equal, because they are not compared by value. These two objects, same as those two strings: text1 and text2, exist physically distinctive in the computer memory. They have the same value, but this time, their references are compared for equality. A reference is equal to another only if they have the same address.

The address is not a complex notion like: reference, variable, value, type, etc. that needs to be defined with a combination of other concepts. The address is simply a natural number and it's quite well defined for every object. Let's say, in 32bit desktop versions of the Windows operating system, the total capacity of addressable memory by the OS is 4294967296 bytes. Those bytes are numbered [0..4294967295] and theoretically any even value in this range can be a valid address for those two objects: object1 and object2.

When JavaScript operator == is comparing object1 and object2, it is comparing the addresses at which those objects exist. For example, if object1 is at address 4000 and object2 is at address 777888, the result of the == comparison operation will be false. If and only if variables object1 and object2 reference the same memory address (example, 123456), the result of operator == will be true. They will reference the same object.

In any language, the reference must represent at least the address of an object, but whatever a JavaScript reference is, beside the address, it's not my business.

Object Creation

There are three ways to create an object in JavaScript and they all employ a function to do it. Usage of function Object.create is not elaborated in this text. It deserves an article of its own.

Let's get back to our first example, creating an object by specifying an object literal and by calling new with constructor Object.

Example 5

JavaScript
var myCar = {
    color: "silver",
    weight: 940
};

//or plainly call the Object constructor

var hisCar = new Object({color: "blue", weight: 1040});

Now you can clearly see that myCar is a Suzuki Baleno and that hisCar is a Hyundai i20, what you cannot see is that the first example of creation implicitly uses the Object constructor. My goal will be to prove that.

JavaScript has prototypal inheritance. Inheritance is a way of code reuse and objects inherit from their prototype, which in turn is just another object. Newly created objects reuse code and data defined in other already existent objects.

The way all objects in the language reference their parent is via their internal [[Prototype]] property. Objects have only one parent which in turn will reference its parent in its [[Prototype]] property...and that linear lookup list is called the prototype chain.

Object myCar is inheriting a lot of functionality, some property methods to name are: hasOwnProperty, isPrototypeOf, propertyIsEnumerable, toString, etc. even though myCar does not implement these methods, it's free to use it.

But, what is the object that implements this method? That would be the "primordial" object. All default reference types: object, functions and arrays inherit from it, if the normal prototype chain is not disrupted.

Alas, this default prototype chain doesn't end with the primordial object, it ends with null. That is, the [[Prototype]] property of the primordial object references null. That's perfectly legal, the primitive value null is also an object.

Example 6

JavaScript
typeof null      //"object"

The "Chicken-and-egg" spiral!

Catch-22

My understanding of JavaScript or anything else for that matter is, I'm looking for facts that build up the rules. It was said that objects are of reference type and that null is one of the primitive types which are not references. That breaks the rules "and when the machine breaks down, we break down".

Not all is lost though, if you have null assigned to two variables, they are equal. Looks like they are compared by value like primitive types. There is another way of looking at this, what if those variables are referencing an object at the same yet invalid address, i.e., null? Either way, you think of null, object or primitive, boolean expressions will give you consistent results.

Things like null, undefined or NaN are hard to reason, but I very much like their ways in JavaScript. The null viewed as an object is a void reference, one of a kind, at which nothing can be instantiated. You can think of it as an non existent, but real sounding country for which there is no place on the map...

On many occasions, null is used as an absence of an object where you would usually get one. Say, by a function call that is supposed to return one from the database. Most notably, null is the last member in the prototype chain.

Similar, undefined is not only an undefined value, but worse. An undefined data type also. NaN is a primitive of type number, but has no numerical value and it is the only value that doesn't equal itself. This not only breaks the rules for primitive types, but also breaks the rules of reference types.

Example 7

JavaScript
NaN === NaN    //false
NaN == NaN     //false

Even, the coercing operator == is not able to return true...

Look at myCar and hisCar in example 5. My premise is that the first case is a use case of the second one.

Every object has a [[Prototype]] property that is a reference to some other object. That property happens to have the same value on myCar as on hisCar. It is a reference to the same primordial object.

Something is setting to myCar and hisCar objects the same [[Prototype]] property. That something is the Object constructor function.

Constructor Mechanics

JavaScript comes with some pre built constructors: Object, Function, Array... Some rules of the language depend on those.

All functions in JavaScript are ready set constructors. We don't intend to use all of them as constructors, but there is no difference between a constructor and a normal function. To make a mental note that a function is planned for a constructor, we write it with a first capital letter. That's a convention.

When used with the new keyword, all functions will return a newly created object. They will all dynamically create a property on that object. Even if you don't intend for them to act as constructors. Even if you don't set anything inside of them. And when I say all, I mean all.

Example 8

JavaScript
function Person(name) {
    this.name = name;
}

function multiplyByTwo(n) {
    return 2*n;
}

var herCar = {
    color: "red",
    weight: 1000,
    honk: function() {
        console.log("honk");
    }
};

var obj1 = new Person("steve");
var obj2 = new multiplyByTwo(4);
var obj3 = new herCar.honk();

Obviously, herCar.honk and myltiplyByTwo do not explicitly set any properties to obj2 and obj3 and yet they set something. Every function has a prototype property which is an object. Every function when called with new is setting its prototype property to be the [[Prototype]] property of the object it constructs. This is a crucial fact. If there is only one thing that you remember after reading this article, let it be this.

Example 9

JavaScript
obj1.__proto__ == Person.prototype                 //true
obj2.__proto__ == multiplyByTwo.prototype          //true
obj3.__proto__ == herCar.honk.prototype            //true
Person.prototype == herCar.honk.prototype          //false
obj2.__proto__ == obj3.__proto__                   //false

Functions are also objects so they too have an internal [[Prototype]] property. The prototype property and the hidden [[Prototype]] property are not the same. The prototype property is default only on functions.

You can set a property called prototype on any object you like. If you have no better idea for fun... You can even set the prototype property of a function to be a primitive value. I could have set the prototype of constructor Person to be the numeric value of 8, but I don't find that funny.

However, you cannot set the [[Prototype]] property of an object to a primitive value.

In this article, the prototype of an object, [[Prototype]] and __proto__, all three things are considered equal and all examples expose this object reference as __proto__.

When you create an object with the object literal notation, its prototype (parent) becomes Object.prototype.

Example 10

JavaScript
myCar.__proto__ == hisCar.__proto__        //true
myCar.__proto__ == Object.prototype        //true

So the prototype chain or the lookup list for data and code reuse of myCar would be: myCar --> Object.prototype --> null.

For obj1, it would be: obj1 --> Person.prototype --> Object.prototype --> null.

When you create your own constructor function, at least, you are inserting one member (object) in the prototype chain between Object.prototype and your newly created object that is returned from the constructor. In this case, the inserted object is Person.prototype.

The prototype property of your constructor function is a very very important object upon which you build all future inheritance for the objects you create.

Example 11

JavaScript
Person.prototype.doubleItsName = function() {
    return this.name + this.name;
}

obj1.doubleItsName()      //"stevesteve"

var Pesonia = function(surname) { this.surname = surname };
Personia.prototype = obj1;
var obj4 = new Personia("mcconnell");

obj4.name                 //"steve"
obj4.surename             //"mcconnell"
obj4.doubleItsName()      //"stevesteve"

I've just set the prototype chain for obj4 to be: obj4 --> obj1 (Personia.prototype) --> Person.prototype --> Object.prototype --> null.

Or should I say: obj4 --> obj4.__proto__ --> obj1.__proto__ --> Object.prototype --> null.

And I can override the name of obj4 and obj1.

Example 12

JavaScript
obj1.name = "joey";
obj4.name = "billy";

And I can reuse the code from obj1 in obj4.

Example 13

JavaScript
obj4.doubleItsName()    //"billybilly"
obj1.doubleItsName()    //"joeyjoey"

In example 11, I didn't have the name property as own property of obj4 so, JavaScript was delegating though the prototype chain of obj4. It did found name on obj1.

Also, the method doubleItsName is not found on obj4, not even on obj1. It is deeper in the prototype chain. It's on an object I have no other name to call than Person.prototype.

The Birth of a Miracle

When you use the new keyword on a function, JavaScript returns a newly constructed object, unless the function is already returning an object. Normally called, function herCar.honk returns undefined and function multiplyByTwo returns a number. They perfectly match that criteria. These two functions do not set anything inside that new object, so it has only the [[Prototype]] property.

As we discovered, the __proto__ property of an object is the prototype property of its constructor. A criminal behaviour of functions is that they set the constructor property of the prototype object to be the function itself, instead as it should be the Object constructor.

So, the constructor property of multiplyByTwo's prototype is set to be the function multiplyByTwo (Chicken-and-egg). Therefore, obj2 which inherits from multiplyByTwo.prototype inherits also this property.

Example 14

JavaScript
multiplyByTwo.prototype.constructor == multiplyByTwo      //true
obj2.__proto__.constructor == multipleByTwo               //true
multiplyByTwo.prototype.hasOwnProperty("constructor")     //true

obj2.constructor == multiplyByTwo                         //true
obj2.hasOwnProperty("constructor")                        //false
obj2.constructor(6)                                       //12

obj2 inherits the constructor property through its prototype chain.

You remember that when I created obj2, I called multipleByTwo with argument 4 (example 8)? Because the newly created object returned as obj2 and parameter n of function multiplyByTwo were in the same scope (JavaScript has function scope), they both exist even after the function multiplyByTwo returns. Whoop-de-doo a closure.

I cannot access argument 4 as parameter n, because I have lost the scope, but the activation object that was created by the execution context when multipleByTwo was running on the execution stack is still there. It has to be, obj2 is part of that same activation object.

I'll redefine multipleByTwo to show you this. Now the newly created object will have a method called giveN.

Example 15

JavaScript
function multiplyByTwo(n) {
    this.giveN = function() {
        return n;
    }
    return 2*n;
}
var obj2 = new multiplyByTwo(5);

obj2.giveN()              //5
obj2.constructor(7)       //14
obj2.giveN()              //7

When I call multiplyByTwo as a constructor with the new keyword, the context, i.e., this in the function changes. It is the newly created object. For that moment, the new object has no other identifier than this and is in the same scope as parameter n. So is the newly anonymous function that returns n, which I assign to this as property giveN.

Upon return of function multiplyByTwo, this will be assigned to obj2 and it will have a member function giveN that was part of the same scope as was obj2 and argument 5. The scope is again lost, but the activation object of the execution context when multiplyByTwo run, is preserved. We've created a closure, because we have a reference to at least one member (obj2, but obj2.giveN also) of that scope.

Now when I run obj2.constructor as a function with a different argument, for instance 7, I get that to be the return value from member function giveN. Why does now the return value from giveN change from 5 to 7? Does multiplyByTwo as a function rewrite parameter n from the closure? Not exactly.

In fact, when you call multiplyByTwo like this obj2.constructor(7) it is not the same as calling multiplyByTwo(7). You are calling that function as a method of obj2 and so this inside the function becomes obj2. Next, you create a new anonymous function that you reassign as property giveN of obj2. You rewrite the old property and that anonymous function only knows of argument 7 as it sees parameter n. You are not recreating obj2 so you still have that old argument 5 and first time created function giveN on the same activation object as obj2, but you have lost reference to them.

Example 16, More Fun

JavaScript
var t;
function multiplyByTwo(n) {
    t = this.giveN;
    this.giveN = function() {
        return n;
    }
    return 2*n;
}
var obj2 = new multiplyByTwo(9);

obj2.giveN()            //9
obj2.constructor(11)    //22
obj2.giveN()            //11
t()                     //9

By the way, if I call multiplyByTwo as a normal function, without the new keyword, I would create a new property on the global object. Function giveN becomes global as a side effect. A good example of how not to do things.

Programming for the Masses, not the Classes

Bill Venners: "But by delegation, you do mean this object delegating to that object without it being a subclass?"
James Gosling: "Yes -- without an inheritance hierarchy. Rather than subclassing, just use pure interfaces. It's not so much that class inheritance is particularly bad. It just has problems."
 

The way I have created Person constructor is not a JavaScript pattern, it's more like what a Java programmer would do.

Example 17

JavaScript
function Person(name) {
    this.itsName = function() {
        return name;
    }
}
var obj1 = new Person("jim");

obj1.itsName()    //"jim"

This is a JavaScript Person constructor. Now you have a, more then private, private name.

The byproduct of nested functions are closures, but the real reason why closures instantiate is in the first classness of functions in JavaScript. The rules that all other variables obey are obeyed by functions, too.

When you call a function in JavaScript and in many other languages, the local variables that are defined inside the function, also called automatic variables, are instantiated at that moment. First class functionality means that local (nested) functions are also instantiated this way automatically and they share the same scope as the local variables. This is something you also want to remember from this article, so I will repeat it. Whenever you call a function that has nested functions defined inside its body, they are all automatically instantiated anew.

Those functions live the same life as the automatic variables. If you happen to return an automatic (nested) function from the outer function to some variable, the garbage collector can no longer dispose of that automatic function from memory, since now you have a reference to it. You can call it. And since that nested function had access to all the peers defined in the same scope of the outer function: local variables, parameters, other local functions and local objects, the garbage collector cannot dispose of its peers too, so we have a closure.

Standard Pascal has nested functions also, but it does not have closures because functions lack first class citizenship. That is to say, it's nested functions are not created anew as local variables, but are created once upon compile time. Only the stack frame of the nested function is created/destroyed at runtime. Static noise...

Other notable built in constructors of JavaScript are: RegExp, Array, Function... As you would have expected, the Function constructor is responsible for creating functions. Consistent to the object construction examples, no matter in what way you create a function.

Example 18

JavaScript
function addTwo(n) { return n+2 }
var addThree = function(n) {return n+3};
var addFour = new Function("n", "return n+4");

addTwo.constructor == addThree.constructor     //true
addThree.constructor == addFour.constructor    //true
addTwo.constructor == Function                 //true
Object.constructor == addThree.constructor     //true
Array.constructor == Function                  //true

All functions are created by the Function constructor. And so, Function.prototype as a rule gets inserted as a [[Prototype]] property to all objects created by it and you know what they say, functions in JavaScript are objects as well.

Example 19

JavaScript
addTwo.__proto__ == Function.prototype    //true
Object.__proto__ == Function.prototype    //true
Array.__proto__ == Function.prototype     //true
RegExp.__proto__ == Function.prototype    //true

What is this object, the Function.prototype? It's a native function. A pice of code that always stays translated in its immediately executable form by the JavaScript engine. One of the most crucial pieces of code in the entire JavaScript runtime. As you can see Function.prototype is Object.__proto__, the most immediate ancestor in the prototype chain of constructor function Object. What is then Function.__proto__?

The rule was that any object's __proto__ property is the constructor's prototype property. What is the constructor of Function?

Example 20, Catch-22

JavaScript
Function.constructor == Function            //true

//even worse

Function.__proto__ == Function.prototype    //true


At last, let's se how a constructor's prototype delegation relates to Function and Object built-in JS constructors, example Person

Person --> Function.prototype --> Object.prototype --> null.

Or: Person --> Object.__proto__ --> Object.prototype --> null.

Functions are somewhat more rich, they have in their prototype chain the primordial function and the primordial object. Objects only inherit the primordial object.

Appendix C

When programmers talk about objects, they talk about the same thing only at the same level of programming languages. There are low level and high level programming languages.

"A high-level programming language is a programming language with strong abstraction from the details of the computer".

For a C programmer, an object is an instance of a data type. For an advanced C++ programmer, it is also an instance of a data type, but they'll more commonly refer to objects as being instances of a class.

Advanced C++ programmers know that only the data members of the class are the once being instantiated. It's methods are static and have only one instance in the text or code segment of the compiled program.

A beginner C++ programmer considers an object to be an instance of a class. A Java (crippled version of C++) developer does not only see objects as instances of a class, but solely as a product of the 'class' keyword.

I advisedly did not say same level of abstraction, but used "the same level of programming languages". Higher level of programming languages are supposed to have a higher level of abstraction. JavaScript being of greater than Java, Java greater than C++ and C++ offering greater level of abstraction over C.

Abstraction can be seen as factoring out common properties from the specific ones, but in this elementary example, a Java object is a special case of a C++ object, being only able to use single inheritance (C++ has multiple). Both, Java and C++ definitions of an object fail into a special case of a C object.

You have to separate that in your head, the concept of object and class.

Don't fool yourself that, because C hasn't got the 'class' keyword, it can't implement classes. "The very first Java compiler was developed by Sun Microsystems and was written in C", "the JRE is written in C" and "Most of the Sun's implementation of Java -JVM- is written in C". C can implement Java features, but it doesn't work the other way around. :)

There are many examples whereby using an instance of a Java class, you end up using an instance of a C class, especially in the Android system where said Java classes are only wrappers around C shared libraries.

If I have to be very brief, I'd say a class is a complete set of definitions of a data type and its accompanying functions. All nicely encapsulated in one file. But, that's just my crude way of saying it.

Here is a more profound statement: "A procedure which is capable of giving rise to block instances which survive its call will be known as a class; and the instances will be known as objects of that class."  - Structured Programming (Dahl, Dijkstra and Hoare)

History

  • 9th December, 2019: Initial version

License

This article, along with any associated source code and files, is licensed under The GNU General Public License (GPLv3)


Written By
Macedonia, the Republic of Macedonia, the Republic of
heretic

Comments and Discussions

 
Questionmultiple inconsistencies between text & code Pin
Member 1465602615-Dec-19 20:44
Member 1465602615-Dec-19 20:44 
AnswerRe: multiple inconsistencies between text & code Pin
Martin ISDN20-Dec-19 8:32
Martin ISDN20-Dec-19 8:32 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.