The differences between the two concerns how "this" is bound within the function calls.
The object on the left of the . in front of the function call is the object which "this" is bound to.
sausagePizza.constructor.prototype.divvyUp();
//sausagePizza.constructor.prototype is left of the .divvyUp()
//so it is bound to this. However, the prototype object does not have
//a type property so it this.type returns undefined
However, for the case of sausagePizza, the constructor did create those properties.
sausagePizza.divvyUp()
//here sausage pizza is to left of .dizzyUp() and "this" is bound to it.
Edit:
To understand prototypes in Javascript it might help to have everything completely spelled out. First Functions are objects, which means that they have properties. Every function is created with some basic properties. One of these is the prototype, which starts out as an empty object.
function Pizza(type, slices) {
this.type = type;
this.slices = slices;
}
console.log(Pizza.prototype) // prints {} an empty object
Pizza.prototype.divvyUp = function () {
alert("The " + this.type + " pizza has been divvied up!");
};
console.log(Pizza.prototype) // prints {divvyUp: [Function]}
Now when we use the new operator in front of a function it creates a new empty object, sets the object __proto__
and constructor properties, and then runs the function with "this" bound as the new object.
var sausagePizza = new Pizza("sausage", 8);
console.log(sausagePizza) // {type: "sausage", slices: 8}
//Objects in javascript can have hidden properties.
//If we unhide the relevant ones for this example
//sausagePizza really looks like this.
{
constructor: Pizza, //the function
__proto__: Pizza.prototype, //the object on the function
type: "sausage",
slices: 8
}
So the . operator actually works by looking into the object on the left for the key on the right (e.g. . ). If it does not find the key it is looking for in the properties object on the left, then it looks into the __proto__
of the object for the key. So when you do
sausagePizza.divvyUp()
//Javascript first looks into sausagePizza for divvyUp.
//It does not find it.
//then it looks for divvyUp in sausagePizza.__proto__
//it find divvyUp there and then () calls the function
//if javascript had not found divvyUp in sausagePizza.__proto__ then it would have
//looked into sausagePizza.__proto__.__proto__ if it existed, and so on