If you don't pay attention to your money, others will.
GreaterThanZero.com


Page 5 of: Object-Oriented Programming in JavaScript Explained, by Thomas Becker   about me  

Prototypes

Recall that our next order of business is to find out how to deal with methods (member functions) in pre-ECMAScript-6 JavaScript. Perhaps the best way to understand this is to first look at how not to do it. Given the constructor function as shown in the previous section, you may be tempted to provide methods such as distance (see the Point class example in Section 3) by adding them to the constructor:
// Bad constructor function
function Point(x, y) {
  this.x = x;
  this.y = y;

  // No! Don't do this!
  this.distance = function(other) {
    return Math.sqrt(Math.pow(this.x - other.x, 2) +
      Math.pow(this.y - other.y, 2));
  };
}
This “solution” will work deceptively well:
var p1 = new Point(0.0, 0.0);
var p2 = new Point(3.0, 4.0);
var dist = p2.distance(p1); // dist is 5.0
The problem, of course, is that this is a double whammy of wastefulness and inefficiency. Firstly, a new copy of the function distance is created for every Point object. So at any given time, your JavaScript program will hold as many copies of the function distance as it has Point instantiations. Secondly, every Point object now has one more property, which, depending on implementation, runtime optimization, and circumstances, may or may not cause additional overhead.

What we really want is a single place where we can put one copy each of the methods distance and getLabel. Furthermore, we want things to be rigged in such a way that when a Point object is asked for a property that it doesn't have, it goes to that magical single place and tries to fetch the missing property from there.

And that's exactly how pre-ECMAScript-6 JavaScript does it. All that remains to be said is where that magical single place is. First, you need to recall that in JavaScript, every object has a property lookup chain consisting of linked objects called prototypes. When a piece of code tries to access a property of an object, as in obj.prop, it is first checked if obj has a property named prop among its own properites. If so, that property is used. If not, the lookup process checks the prototype objects along the chain for a property named prop. When such a property is found in some prototype proto, the lookup process ends and the value of proto.prop is used for obj.prop. Otherwise, obj.prop is undefined.

By default, an object's property lookup chain consists of a single prototype, namely, Object.prototype, as shown in Figure 1. That's why methods such as hasOwnProperty and toString can be called on any object. In the special case where an object is created with the new operator, as in

var p = new Point(0.0, 0.0);
an additional prototype object is inserted at the beginning of the chain. This prototype object
  • is the same for all Point instances,
  • starts out empty as far as property lookup is concerned,
  • and can be accessed via Point.prototype.
It is therefore the ideal candidate for that magical single place where we want to put the Point methods. The entire setup is illustrated in Figure 2. Thus, the complete pre-ECMAScript-6 JavaScript implementation of the Point class of Section 3 is:
//
// The equivalent of the Point class in pre-ECMAScript-6 JavaScript
//

function Point(x, y) {
  this.x = x;
  this.y = y;
}

Point.prototype.distance = function(other) {
  return Math.sqrt(Math.pow(this.x - other.x, 2) +
    Math.pow(this.y - other.y, 2));
}

Point.prototype.getLabel = function() {
  return "(" + this.x.toFixed(2) + ", " + this.y.toFixed(2) + ")";
};
Notice that when you refer to fields such as x and y inside a method, you have to qualify them with this, as in this.x.toFixed(2) in getLabel above. That's easy to forget as it is optional in traditional class-based languages.

Here's the quintessential use of points again:

var p1 = new Point(0.0, 0.0);
var p2 = new Point(3.0, 4.0);
var dist = p2.distance(p1); // dist is 5.0
To reiterate, the property access p2.distance in the third line of this code now works as follows: First, it is checked if the object p2 has distance as an “own” property. If that were the case, it would be used. Since p2 does not have such an “own” property, lookup proceeds to the object Point.prototype. Since a property named distance is found there, its value is fetched and used as if it were a property of p2. In particular, p2 becomes the receiver of the function call p2.distance(p1), meaning that inside the function distance, the special variable this is bound to p2.

For most JavaScript application programmers, this is all there is to know: the prototype that is common to all Point instantiations is accessed via the constructor, as in Point.prototype, and the technicalities of an object's property lookup along the prototype chain are an implementation detail that is of no concern to the programmer. In certain rare situations having to do with introspection, it is not possible to access the prototype via the constructor because the name of the constructor is not known. JavaScript allows you to access an object's prototype directly from the object, without any reference to the constructor. However, this has only recently been standardized and is therefore difficult to do in a way that is portable and backwards compatible. Don't go there unless you absolutely have to. Items 30, 31, 32, and 41 of David Herman's Effective JavaScript have details and advice.

A Word on Terminology
As mentioned earlier, JavaScript objects that are created with the Point constructor are often called Point instances, or instantiations of Point. This is consistent with the behavior of JavaScript's instanceof operator:
var p = new Point(0.0, 0.0);
p instanceof Point; //true
But what kind of thing is Point? Technically, it is a constuctor function. But since there can be instances of it, many in the JavaScript community also call it a class. That's a bit odd, though, because everybody agrees that JavaScript is classless. It has also been called a type, or custom type. That's promising because JavaScript has the notion of data types, such as Number, String, etc. Unfortunately, though, the JavaScript typeof operator informs us that Point is not a data type:
var p = new Point(0.0, 0.0);
typeof p; //returns 'object'
The bottom line is that as far as terminology is concerned, I don't know what Point is (or perhaps more precisely, the combination of the constructor function Point and the prototype Point.prototype). Some guidance from an authoritative source would be helpful in this matter.