Demystifying Prototype In JavaScript



First thing you need to understand with JavaScript is that there is no such thing as classes(ignoring the ES6 spec). JavaScript is filled with an endless sea of objects. Objects are linked to each other, the idea of classes is a mere design pattern that can be implemented via mixins. I'll cover the fundamentals of OO JavaScript in a future post but I just wanted to preface this topic by setting the stage clear on where JavaScript stands in regards to classes.

JavaScript descendants

At the heart of it, all JavaScript objects descend from Object. There is nothing magical about Object, it can be thought of as a set of name/value pairs where the name is a string and the value is any JavaScript type. Don't believe the religious debates about how JavaScript doesn't have types, there are plenty of them. More on this in another post(I promise).


descendant confused baby lol

The super parent Object has two properties, length and prototype. Prototype is the link that allows for JavaScript objects to link together. There are a boat load of methods on the base Object object but I won't go into them here and instead focus on the prototype property. One key thing to remember is that since all objects are descendants of Object, they all take on the prototype property!


I'm Lost, give me some examples!

So let's say you've never heard of prototype but you have heard of prototypal inheritance. Just as a *warning* the traditional sense of inheritance has a completely different meaning in JavaScript than it does in other statically typed languages such as C#(more on this in another post). Okay so here's a starting example


    var Vehicle = {
 	  cylinders: 4
    }
    var Car = new Object(Vehicle);

    console.log(Car.cylinders); //4
    Car.passengers = 2;
    console.log(Car.passengers); //2


confused sign right left lol

What just happened in that code? We didn't define the property cylinders on the object Car, so how can we set a value to it? What actually happens here during the engine execution step when the engine encounters Car.cylinders is call the GET operation. The GET operation first checks whether or not cylinders exists on the Car object. Does it? Obviously not from our declaration step, so why doesn't the code blow up? This is the magic of JavaScript and the prototype property!

Since the passenger property doesn't exist, GET starts to fish up the prototype chain. Remember, all objects have the prototype property. Let's chain this object further to help understand JavaScript prototype chain linking:


    var Steel = {
        carbon: 2,
        iron: 90,
        others: 8
    }
    var Chassis = new Object(Steel);
    var Assembly = new Object(Chassis)
    var Car = new Object(Assembly);

    console.log(Car.iron) // 90
    console.log(Car.passengers); //undefined


car mold model new prototype

Inheritance?

NO! What is happening above is that Car is linked all the way up the chain to the Steel object via prototypal linking. Car does not actually inherit the properties of Steel, but when the property iron is called, the GET operation begins to check up the prototype chain to see if it can find the property. The Car object delegates responsibility up the chain.

First step up the prototype link from Car is Assembly, does it have iron or passenger? Nope, how about the next prototype link up to Chassis? Nope, how about Steel? YES! we just found iron, and thus we can return the value which is 90. The same series of steps occurs for passengers except when we get to Steel we are still scrambling for the missing passengers property. Once we traversed all the way up the tree to the baseObject.prototype and we still don't have a property passengers then the return value is undefined! In JavaScript(ES5) this prototype chain is spanned through the GET operation.

Shadowing properties

    var Steel = {
        carbon: 2,
        iron: 90,
        others: 8
    }
    var Chassis = new Object(Steel);
    var Assembly = new Object(Chassis)
    Assembly.paint = "bare rust";
    var Car = new Object(Assembly);

    console.log(Car.paint); //"bare rust"
	Car.paint = "white"
    console.log(Car.paint); //"white"


jedi mind tricks lol droids droid

No Jedi shadowing mind tricks here. Although you may instinctively think that Car inherited the properties of Assembly and all you're doing is shadowing the value of the paint property, that only happens if you used Object.defineProperty() and explicitly defined the key on the car object. Implicit shadowing is very dangerous as it may happen unknowingly. Shadowing only occurs when the property is not marked as read-only!

Prototype is cool but what is __proto__

In this whole discussion we just masked __proto__ which is the actual object used in the chain lookup, whereas prototype is a property/object that builds __proto__ when a new object is linked via the new keyword. I would highly recommend against using __proto__ as its been "deprecated" since browsers like to implement it in different ways. ES6 standardized __proto__ but for now it's best to avoid it. Here's an example of __proto__ in action.

    var Steel = function(){
        this.carbon = 2,
        this.iron = 90;
    }

    var Sword = new Steel();

    console.log(Sword instanceof Steel); //true
    console.log(Sword.iron); //90
    console.log(Sword.__proto__ == Steel.prototype); //true


Happy coding and feel free to leave me a message or shoot me an email!

keep calm and keep learning javascript
[Date Edited: 7/8/2016 6:21:43 AM ]

Leave a Comment