0

I have following piece of code for the purpose of learning JavaScript.

function Pizza(type, slices) {
    this.type = type;
    this.slices = slices;
}


Pizza.prototype.divvyUp = function () {
    alert("The " + this.type + " pizza has been divvied up!");
};

var sausagePizza = new Pizza("sausage", 8);


sausagePizza.constructor.prototype.divvyUp();
sausagePizza.divvyUp();
if (sausagePizza.constructor.prototype.divvyUp === sausagePizza.divvyUp)
{
    alert("yes they are equal");
}

The thing is that when these two lines of code are executed:

sausagePizza.constructor.prototype.divvyUp();
sausagePizza.divvyUp();

Though the if statement next to them ratifies that they are equal as far their types and values are concerned. But the First line gives me a result which reads like this "The undefined pizza has been divvied up" and the second line turns out to be giving me a little different result which reads as "The sausage pizza has been divvied up". I'm super confused that why can't first line among these two read this.type variable value and throws an undefined from the alert message inside divvyUp() function when they are equal according to the if statement.

user2913184
  • 566
  • 10
  • 29
  • function is first class citizen in javascript. you can call the same function on different objects and that's what you are doing. – webduvet May 31 '15 at 22:34
  • `sausagePizza` has a `type`, while `sausagePizza.constructor.prototype` does not. – andars May 31 '15 at 22:35
  • the first line calls your function on global object, the second on your sausagePizza. – webduvet May 31 '15 at 22:36
  • @webduvet but how come sausagePizza and sausagePizza.constructor.prototype are different objects, what I though that it's just the different syntax to write the same object in JS. – user2913184 May 31 '15 at 22:40
  • @user2913184 nope. they are indeed very different two objects. your sausagePizza is brand new object created with `new` keyword. – webduvet May 31 '15 at 22:43
  • @user2913184 the whole idea of prototypes is that they're a blueprint for creating new objects, so any time you use `new` or `Object.create()` you will get a new object that's different from the prototype. It works using delegation so if it doesn't find the property on your object, then it looks in the prototype. See http://robotlolita.me/2011/10/09/understanding-javascript-oop.html – Matt Browne May 31 '15 at 22:44
  • 2
    possible duplicate of [How does JavaScript .prototype work?](http://stackoverflow.com/questions/572897/how-does-javascript-prototype-work) – Matt Browne May 31 '15 at 22:47
  • 2
    possible duplicate of [How does the "this" keyword work?](http://stackoverflow.com/questions/3127429/how-does-the-this-keyword-work) – Robert Rossmann May 31 '15 at 22:49
  • The thing is when I execute sausagePizza.constructor it gives me the value of Pizza constructor, and if that is true then Pizza.prototype and sausagePizza.constructor.prototype should be the same object, which I guess they are. Does this mean that sausagePizza is the prototype object of Pizza? – user2913184 May 31 '15 at 23:05
  • if sausagePizza is prototype of Pizza then sausagePizza.constructor.prototype should be the same object as sausagePizza. – user2913184 May 31 '15 at 23:13
  • 1
    You have it backwards. Pizza.prototype is the prototype of sausagePizza. Yes, Pizza.prototype and sausagePizza.constructor.prototype are the same object (since sausagePizza.constructor points to Pizza). – Matt Browne May 31 '15 at 23:28
  • Oh my gosh, its in the backward direction. Ok, if Pizza.prototype is the prototype of sausagePizza then who or what is the prototype of Pizza itself? – user2913184 May 31 '15 at 23:30
  • 1
    Pizza is a constructor function, and like any other function (all functions are also objects) its prototype is Function.prototype. Constructor functions make all of this a little harder to learn, because Pizza.prototype doesn't actually refer to the prototype of the Pizza constructor function, but rather is only used by JS when setting the prototype of new instances of Pizza. – Matt Browne May 31 '15 at 23:42
  • 1
    This example which doesn't use constructor functions at all might help clarify things: http://jsfiddle.net/uutyb82d/. I don't write my own code that way but it might be helpful for illustrative purposes. I used getter and setter functions which don't work in IE8 and below...the reason I used them was so I could show a way of safely putting data properties on the prototype. Ordinarily I avoid that because it can lead to unintentionally shared prototype properties. See http://www.bennadel.com/blog/1566-using-super-constructors-is-critical-in-prototypal-inheritance-in-javascript.htm – Matt Browne May 31 '15 at 23:44
  • 1
    Oh, and in my jsfiddle example, the prototype of sausagePizza is simply pizza - that's what Object.create() does. – Matt Browne May 31 '15 at 23:46
  • Oh boy, now I see why so many c# programmers say no to JavaScript. – user2913184 May 31 '15 at 23:53
  • Some would say (and I tend to agree) that the prototypal model of Javascript is actually better in many ways than class-based programming. Its OO model was based on that of the "Self" language, which was very thoughtfully designed. See http://www.cs.ucsb.edu/~urs/oocsb/papers/organizing.pdf. Unfortunately the Javascript implementation of prototypes is far more confusing for beginners and has some unfortunate quirks. If you want truly object-oriented programming you should check out DCI, invented by the creator of MVC: http://fulloo.info/ – Matt Browne Jun 01 '15 at 00:00
  • 1
    I guess I can make you my JS guru if u don't mind. So can you send me a mail on my personal id which is vandy.aisinfotech@gmail.com. But choice is yours no insistence from my side, still I would say I respect and salute people with lot of programming knowledge like yourself. – user2913184 Jun 01 '15 at 00:06

1 Answers1

2

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
Hath995
  • 444
  • 4
  • 10