User Tools

Site Tools


javascript:prototypes:the_prototype

This is an old revision of the document!


The Prototype

This is 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`.1)

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.');

};

Even further, 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 in `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 that whose values are common to all objects: */

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. */

1)
The use of the `__proto__` identifier for this is true of broswers; in Node.js it might be different.
javascript/prototypes/the_prototype.1533939967.txt.gz · Last modified: 2018/08/10 22:26 by mithat

Donate Powered by PHP Valid HTML5 Valid CSS Driven by DokuWiki