Arieh.co.il

Javascript Guide - The Prototype

You can now also navigate the guide through the table of contents.

On previous posts we learned about objects, functions and scope resolutions. This post will mix these 3 tools, and together we will have a very good image of what makes JS different.

As mentioned before, everything in JS is an object. That puts the language within the object-based family of languages. But in it's core, Javascript is prototype based.

In order to understand the concept of prototypes we need to start with a few other concepts.

The this keyword

When we create an object, for example through the object literal syntax, we end up with a wrapped up group of variables warped together. But this can be nice by itself, but it can be much more.

Using the this keyword, members of an object (members are variables within an object) can access a reference to the object, and thus, to each other.

How does it work?

        var Person = {
            'name' : ''
            , 'family' : ''
            , 'whoAmI' : function(){
                console.log('I am ' + this.name + ' ' + this.family);
            }
        };
        Person.name = 'arieh';
        Person.family = 'glazer';
        Person.whoAmI(); // I am arieh glazer
    
run code

As you can see, the method whoAmI uses the this keyword to reference it's object's members.

There is a thumb rule on how to know who this points to - It always points to one scope above. So in our case - the whoAmI parent scope is Person, and so it points to it.

Constructors

So far not so hard. But now - we need to understand constructors. So far, we used functions by simply calling them. But there is a different, very powerful way of using functions- the new operator.

If we were to use the this keyword within a function, it will point to it's parent scope. So with this example:

    function useThis(){
        this.a = 'b';
    }
    
    useThis();
    console.log(a); //b
    
run code

this will point to the parent scope - the global one, and create a global variable by the name of a.

But, if we use the new keyword on the function, it will instead create a new instance wrapping the scope, holding the functions this:

    function useThis(){
        this.a = 'b';
    }
    
    var use = new useThis();
    
    console.log(use.a); //b
    
run code

This use of functions is called constructors, which means the function is used to construct a new instance of an object. Now let's look at a better use of constructors, reimplementing our Person object:

    function Person(name){
        this.name = name;
        this.whoAmI = function(){
            console.log("I Am "+name);
        }
    }
    
    var bob = new Person('Bob')
        , alice = new Person('Alice');
        
    bob.whoAmI();// I Am Bob
    alice.whoAmI(); // I Am Alice
    
run code

As you can see, we can use constructors to automate the creation of objects. But there is another, very important aspect to new we created a new type in a program - Person, and both bob and alice are instances of that new type. What they both share, is a prototype.

Prototype

And we're back on track. You see, a prototype is kind of like a way for the interpreter to identify a group of variables as ones of the same family. Whenever use the new operator, the prototype of the new variable is set to that of the constructor. Whenever we try to access a member or method of a variable, the interpreter will see if that variable has them, and if not, it will start looking up the variable's prototype tree for it.

Now, This was a bit confusing, so some examples are due.

    function Person(name){
        this.name = name;
    }
    
    //we set whoAmI to the Person's prototype
    Person.prototype.whoAmI = function(){
        console.log('I Am '+this.name);
    }
    
    var bob = new Person('Bob')   //both prototype point to Person.prototype
        , alice = new Person('Alice');
    
    Person.whoAmI = function(){console.log('no one');} // this doesn't change the prototype
    
     //thus not affecting bob and alice
    bob.whoAmI(); // I Am Bob
    alice.whoAmI();// I Am Alice
    
    Person.prototype.getName= function(){return this.name;} // this sets a new method to the prototype
    
    console.log( bob.getName() ); //which bob now inherits - logs Bob
    
run code

I know this can be quite confusing, but it is this one base aspect of ECMAScript that makes it completely unique from all other languages. It is this aspect that let's us do some very neat tricks, and create a very reach repository of design patterns.

Just to make this even more interesting, we will return to our recurring statement - everything is an object. This means that even strings and numbers have prototypes we can manipulate. So, if we want, for example, to add a method to all strings-

    String.prototype.addA = function(){
        return this + 'a';
    }
    
    var word = 'abc';
    console.log(word.addA()); //abca
    
run code

In the next post we will start looking at some advanced patterns in JS. You should continue only after you've freshened up.

JavaScript Reference, JavaScript Guide, JavaScript API, JS API, JS Guide, JS Reference, Learn JS, JS Documentation