====== The JavaScript Prototype ====== This is the first in a series of articles intended as a gentle guide through the realm of JavaScript prototypes. If you’re coming here from a class-based language like Java, PHP, C#, or C++ I suggest you put aside everything you know about how objects and inheritance work in those languages. Try to treat the way JavaScript works as its OwnThing. ===== Context and Motivations ===== You probably know how to create an object literal – say for a person: var fuzz = { name: 'Fuzz', greeting: 'Hello. My name is', sayName: function () { console.log(this.greeting, this.name); } }; This works fine for one-off objects. If you need to create more than one person, you could create a factory function: function makePerson(name) { return { name: name, greeting: 'Hello. My name is', sayName: function () { console.log(this.greeting, this.name); } }; } var fuzz = makePerson('Fuzz'); var athena = makePerson('Athena'); or a constructor function: function Person(name) { this.name = name; this.greeting = 'Hello. My name is', this.sayName = function() { console.log(this.greeting, this.name); } } var fuzz = new Person('Fuzz'); var athena = new Person('Athena'); In both of the above, ''%%fuzz%%'' and ''%%athena%%'' each have their very own copies of ''%%name%%'', ''%%greeting%%'', and ''%%sayName%%''. For a small set of small objects, this is fine. But consider that every Person so defined has properties whose values are common to all Persons (''%%sayName%%'' and, arguably, ''%%greeting%%''). Wouldn’t it be nice if there was a convenient place where we could put shared stuff like this and only refer to that one copy instead of making each object carry around its own copy? This could save a lot of memory if there are a lot of Persons or if a shared property happens to be really big. Also, what if we want to create a kind of Person that, say, is a bit more specialized – like a Teacher. A teacher might be identical to a Person except that they have an additional ''%%subject%%'' property and a ''%%saySubject%%'' method. Wouldn’t it be nice if we could just specify how a Teacher is special in relation to a Person rather than copy/paste the code we already wrote for Person? ===== Enter the Prototype ===== JavaScript offers a solution to both of these via the **prototype**. Every //function// in JavaScript automatically gets a special property attached to it called ''%%prototype%%'': function bar () { }; console.log(bar.prototype); A ''%%prototype%%'' is an object with a bunch of properties, including, curiously, one called ''%%constructor%%'' that points back to the function itself. if (bar.prototype.constructor === bar) { console.log("That's cute."); } else { console.log('You lied.'); }; Going further, when you instantiate an //object// it will automatically recieve a property called ''%%__proto__%%'' that is a reference to its constructor’s ''%%prototype%%''. ((The use of the ''%%__proto__%%'' identifier for this function appears to be true of browsers. In Node.js it might be different.)) function Person(name) { this.name = name; this.greeting = 'Hello. My name is', this.sayName = function() { console.log(this.greeting, this.name); } }; var fuzz = new Person('Fuzz'); if (fuzz.__proto__ === Person.prototype) { console.log("That's cute."); } else { console.log('You lied.'); }; If you try to access an object’s property, the JavaScript engine will first look in the object itself for it; if it doesn’t find it there, it will look in ''%%__proto__%%'' (i.e., the constructor’s ''%%prototype%%'') for it. Let’s set a property on ''%%Person.prototype%%'' and see what happens: Person.prototype.deepDarkSecret = "I descended from apes." if (fuzz.hasOwnProperty('deepDarkSecret')) { console.log('Haz secrets.') } else { console.log('No secrets.') } No secrets. console.log( fuzz.deepDarkSecret ); Oops! The ''%%deepDarkSecret%%'' is actually a property in ''%%Person.prototype%%'', a.k.a., ''%%fuzz.__proto__%%''. if (fuzz.deepDarkSecret === fuzz.__proto__.deepDarkSecret) { console.log("That's cute."); } else { console.log('You lied.'); }; And when we added it to the prototype, it became available to all instances of Person. athena = new Person("Athena"); console.log(athena.deepDarkSecret); ===== Not just a cute party trick ===== The upshot of this is that a constructor’s ''%%prototype%%'' is a convenient place to stuff the properties of objects made with it whose values are common to all objects. Most methods fit into this category as well as potentially other properties: function Person(name) { this.name = name; } Person.prototype.greeting = 'Hello. My name is'; Person.prototype.sayName = function() { console.log(this.greeting, this.name); }; var fuzz = new Person('Fuzz'); var athena = new Person('Athena'); fuzz.sayName(); athena.sayName(); ''%%fuzz%%'' and ''%%athena%%'' now each have their own ''%%name%%'' properties. However, they are using the common ''%%greeting%%'' and ''%%sayName%%'' properties, saving the memory it would have required for them to have their own copies of those. When you ask ''%%athena%%'' to say her name, the JavaScript engine first looks for the ''%%sayName%%'' identifier in the ''%%athena%%'' object. But it won’t find it there. So the next place it looks is ''%%athena.__proto__%%'' – which is the constructor’s ''%%prototype%%'' – and it finds it there. if (fuzz.name !== athena.name) { console.log("That's what I expeceted.") } else { console.log("You lied.") } if (fuzz.greeting === athena.greeting) { console.log("That's what I expeceted.") } else { console.log("You lied.") } if (fuzz.sayName === athena.sayName) { console.log("That's what I expeceted.") } else { console.log("You lied.") } [[#|Next]] we’ll have a look at what happens when you manipulate properties you’ve set on prototypes.