So, on the subject of prototypes an example seemed to be in order…


Suppose I have a year object:

    function Year(number, era){
        this.number = number;
        this.era = era;
    }

Now how do I make a method for this new object that belongs to the object. Is it just:

    Year.prototype.functionName= function();


Ok… there are various ways you can go with this. They all get you slightly different results.

Adding a method to the prototype of Year

This is what you said. Just do…

    Year.prototype.reverse = function() {
        this.number = this.number.split("").reverse().join("");
    }

This way there's only 1 function. On the prototype of Year. When you do…

    var currentYear = new Year("2015", "A.D.");
    currentYear.reverse();

reverse is called by walking up the prototype chain and all that.

Adding it to each object created

This would be doing…

    function Year(number, era){
        this.number = number;
        this.era = era;
        this.reverse = function() {
            this.number = this.number.split("").reverse().join("");
        }
    }

The final result is the same and you can use it in the same way, but now, each object created has its own reverse method and there's no need to use the prototype.

Which of the two is better? None. Both. I mean, they both have advantages. Using the prototype you would generally use less memory. But attaching the method to each object allows you to use private properties. (more on this in a moment)

Writing a getter and a setter is mostly useless in this example as it is. All properties (number and era) are publicly accessible. So having…

    Year.prototype.getYear = function() {
        return this.number;
    }

…or…

    function Year(number, era){
        this.getYear = function() { return this.year; };
    }

…can simply be achieved by accessing directly…

    currentYear.year;

How can we get private stuff and have getters and setters make sense?

Using the prototype we cannot do it. That's just a limitation of how all this works in JS. There is simply no way to have something private and access it from a prototype's method. But doing things in the second way we can do it, to some extent.

    function Year(number, era){
        var number = number;
        var era = era;
        this.getYear = function() { return number; };
        this.setYear = function(newYear) { number = newYear; };
        this.reverse = function() {
            number = number.split("").reverse().join("");
        }
    }

This achieves privacy.

    var currentYear = new Year("2015", "A.D.");
    currentYear.reverse();
    currentYear.getYear(); // "2015"
    currentYear.year; // Doesn't work! Yeah!

Now, about extension… We're going to make a PrintableYear that extends Year and has an additional method printInNaturalLanguage. In this case, we want to build a hierarchy and share methods so we have to use the prototype and thus we have to do away with privacy. In any case, we could do something like this…

    function Year(number, era){
        this.number = number;
        this.era = era;
    }
    Year.prototype.reverse = function() {
        this.number = this.number.split("").reverse().join("");
    }
    function PrintableYear(number, era, morestuff) {
        Year.call(this, number, era); // trick! [1]
        this.morestuff = morestuff;
    }
    PrintableYear.prototype = new Year(); // inheritance!!! :)
    PrintableYear.prototype.printInNaturalLanguage = function() {
        console.log("oh, uh... something something " + this.number);        
    }

    var currentYear = new Year("2015", "A.D.");
    var currentPrintableYear = new PrintableYear("2015", "A.D.");

    var years = [currentYear, currentPrintableYear];

    for (var i=0; i<2; i++) {
        years[i].reverse(); // polymorphism!!! :)
    }

    currentPrintableYear.printInNaturalLanguage();

Note [1] in the code. It's not really much of a trick. You could also simply do this.number = number; this.era = era;, but this way we avoid repetition and use the code already in Year's constructor.

So the polymorphism works because in a sense both currentYear and printableYear are extensions of Year, right?

Yes… almost. In other languages polymorphism works based on what the objects are. So the compiler would check the type of currentYear and printableCurrentYear and say “this is ok”. In Javascript it works just because both objects have a reverse method. This is what duck typing means.

Just imagine the example exactly as it is, but in the end we add…

    ...
    var currentYear = new Year("2015", "A.D.");
    var currentPrintableYear = new PrintableYear("2015", "A.D.");
    
    var thisIsNotAYear = {
        reverse: function() { console.log("hi, there!"); }
    };

    var years = [currentYear, currentPrintableYear, thisIsNotAYear ];
    
    for (var i=0; i<2; i++) {
        years[i].reverse(); // polymorphism!!! :)
    }

This still works. Because in JS polymorphism is not based on types. If the object has whatever property we try to use, then it's fine to use it. This is why I said that polymorphism in JS is simpler, because it doesn't really care about where the object comes from or what kind of object it is.