Object literals and prototypes in JavaScript

You think you know JavaScript and then little things like this happen...

My co-worker Aaron who is a Visual Design Engineer is in the process of learning JavaScript and he asked me to have a look at a Fiddle.

The contents of the fiddle looked like this...

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

// Using this method of adding to the prototype doesn't log out the constructor correctly on lines 21-22...
Pizza.prototype = {  
  divvyUp: function () {
    alert("The " + this.type + " pizza has been divvied up!");
  }
};

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

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

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

He was pointing out to me the fact that when he assigns the Pizza.prototype to an object, the console doesn't show what he expects to see.

Sure enough even at first I was like, wut?

Then I stopped to think about it a bit further.

Whenever I usually work with assigning things to the prototype, I will either do like his second example...

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

Or use jQuery or underscore's extend method...

_.extend(Pizza.prototype, {  
   divvyUp: function() {}
});

These two methods usually work just fine.

So, why was his example all funkyfied? Well, by assigning an object to the prototype, he decoupled the prototype chain. Now all the sudden Pizza.prototype.constructor actually points to the Object constructor rather than the Pizza constructor.

You can see this is the case by logging the instance...

console.log(sausagePizza.constructor === Object); // true  

When you assign a prototype to an object you've changed the prototypical inheritance of that object. The prototype of the object will no longer have the original constructor function!

If you really wanted to use an object literal in this way you can fix it by...

Pizza.prototype.constructor = Pizza;  

Or you could just use the $.extend or _.extend if you really had your heart set on using an object literal for setting the prototype chain up.

Helping people understand JavaScript is one of the best ways to make sure YOU fully understand JavaScript.

Jonathan Creamer

Read more posts by this author.

comments powered by Disqus