Using Prototype Property in JavaScript

Exclusive offer: get 50% off this eBook here
Object-Oriented JavaScript

Object-Oriented JavaScript — Save 50%

Create scalable, reusable high-quality JavaScript applications and libraries

$23.99    $12.00
by Stoyan Stefanov | August 2008 | AJAX Web Development

In this article by Stoyan Stefanov, you'll learn about the prototype property of the function objects. Understanding how the prototype works is an important part of learning the JavaScript language. After all, JavaScript is classified as having a prototype-based object model. There's nothing particularly difficult about the prototype, but it is a new concept and as such may sometimes take some time to sink in. It's one of these things in JavaScript (closures are another) which, once you "get" them, they seem so obvious and make perfect sense. As with the rest of the article, you're strongly encouraged to type in and play around with the examples; this makes it much easier to learn and remember the concepts.

The following topics are discussed in this article:

  • Every function has a prototype property and it contains an object
  • Adding properties to the prototype object
  • Using the properties added to the prototype
  • The difference between own properties and properties of the prototype
  • __proto__, the secret link every object keeps to its prototype
  • Methods such as isPrototypeOf(), hasOwnProperty(), and propertyIsEnumerable()

The prototype Property

The functions in JavaScript are objects and they contain methods and properties. Some of the common methods are apply() and call() and some of the common properties are length and constructor. Another property of the function objects is prototype.

If you define a simple function foo() you can access its properties as you would do with any other object:

>>>function foo(a, b){return a * b;}
>>>foo.length

2

>>>foo.constructor

Function()

prototype is a property that gets created as soon as you define the function. Its initial value is an empty object.

>>>typeof foo.prototype

"object"

It's as if you added this property yourself like this:

>>>foo.prototype = {}

You can augment this empty object with properties and methods. They won't have any effect of the foo() function itself; they'll only be used when you use foo()as a constructor.

Adding Methods and Properties Using the Prototype

Constructor functions can be used to create (construct) new objects. The main idea is that inside a function invoked with new you have access to the value this, which contains the object to be returned by the constructor. Augmenting (adding methods and properties to) this object is the way to add functionality to the object being created.

Let's take a look at the constructor function Gadget() which uses this to add two properties and one method to the objects it creates.

function Gadget(name, color) { 
  this.name = name;
  this.color = color;
  this.whatAreYou = function(){
   return 'I am a ' + this.color + ' ' + this.name;
  }
}

Adding methods and properties to the prototype property of the constructor function is another way to add functionality to the objects this constructor produces. Let's add two more properties, price and rating, and a getInfo() method. Since prototype contains an object, you can just keep adding to it like this:

Gadget.prototype.price = 100;
Gadget.prototype.rating = 3;
Gadget.prototype.getInfo = function() {
  return 'Rating: ' + this.rating + ', price: ' + this.price;
};

Instead of adding to the prototype object, another way to achieve the above result is to overwrite the prototype completely, replacing it with an object of your choice:

Gadget.prototype = { 
  price: 100,
  rating: 3,
  getInfo: function() {
   return 'Rating: ' + this.rating + ', price: ' + this.price;
  }
};

Using the Prototype's Methods and Properties

All the methods and properties you have added to the prototype are directly available as soon as you create a new object using the constructor. If you create a newtoy object using the Gadget() constructor, you can access all the methods and properties already defined.

>>> var newtoy = new Gadget('webcam', 'black');
>>> newtoy.name;

"webcam"

>>> newtoy.color;

"black"

>>> newtoy.whatAreYou();

"I am a black webcam"

>>> newtoy.price;

100

>>> newtoy.rating;

3

>>> newtoy.getInfo();

"Rating: 3, price: 100"

It's important to note that the prototype is "live". Objects are passed by reference in JavaScript, and therefore the prototype is not copied with every new object instance. What does this mean in practice? It means that you can modify the prototype at any time and all objects (even those created before the modification) will inherit the changes.

Let's continue the example, adding a new method to the prototype:

Gadget.prototype.get = function(what) { 
  return this[what];
};

Even though newtoy was created before the get() method was defined, newtoy will still have access to the new method:

>>> newtoy.get('price');

100

>>> newtoy.get('color');

"black"

Own Properties versus prototype Properties

In the example above getInfo() used this internally to address the object. It could've also used Gadget.prototype to achieve the same result:

Gadget.prototype.getInfo = function() { 
  return 'Rating: ' + Gadget.prototype.rating + ', price: ' + Gadget.prototype.price;
};

What's is the difference? To answer this question, let's examine how the prototype works in more detail.

Let's again take our newtoy object:

>>> var newtoy = new Gadget('webcam', 'black');

When you try to access a property of newtoy, say newtoy.name the JavaScript engine will look through all of the properties of the object searching for one called name and, if it finds it, will return its value.

>>> newtoy.name

"webcam"

What if you try to access the rating property? The JavaScript engine will examine all of the properties of newtoy and will not find the one called rating. Then the script engine will identify the prototype of the constructor function used to create this object (same as if you do newtoy.constructor.prototype). If the property is found in the prototype, this property is used.

>>> newtoy.rating

3

This would be the same as if you accessed the prototype directly. Every object has a constructor property, which is a reference to the function that created the object, so in our case:

>>> newtoy.constructor

Gadget(name, color)

>>> newtoy.constructor.prototype.rating

3

Now let's take this lookup one step further. Every object has a constructor. The prototype is an object, so it must have a constructor too. Which in turn has a prototype. In other words you can do:

>>> newtoy.constructor.prototype.constructor

Gadget(name, color)

>>> newtoy.constructor.prototype.constructor.prototype

Object price=100 rating=3

This might go on for a while, depending on how long the prototype chain is, but you eventually end up with the built-in Object() object, which is the highest-level parent. In practice, this means that if you try newtoy.toString() and newtoy doesn't have an own toString() method and its prototype doesn't either, in the end you'll get the Object's toString()

>>> newtoy.toString()

"[object Object]"

Overwriting Prototype's Property withOwn Property

As the above discussion demonstrates, if one of your objects doesn't have a certain property of its own, it can use one (if exists) somewhere up the prototype chain. What if the object does have its own property and the prototype also has one with the same name? The own property takes precedence over the prototype's.

Let's have a scenario where a property name exists both as an own property and as a property of the prototype object:

function Gadget(name) { 
  this.name = name;
}
Gadget.prototype.name = 'foo';

"foo"

Creating a new object and accessing its name property gives you the object's ownname property.

>>> var toy = new Gadget('camera');
>>> toy.name;

"camera"

If you delete this property, the prototype's property with the same name"shines through":

>>> delete toy.name;

true

>>> toy.name;

"foo"

Of course, you can always re-create the object's own property:

>>> toy.name = 'camera';
>>> toy.name;

"camera"

 

Object-Oriented JavaScript Create scalable, reusable high-quality JavaScript applications and libraries
Published: July 2008
eBook Price: $23.99
Book Price: $39.99
See more
Select your format and quantity:

Enumerating Properties

If you want to list all properties of an object, you can use a for-in loop. In Chapter 2, you saw how you could loop through all the elements of an array:

var a = [1, 2, 3];
for (var i in a) {
  console.log(a[i]);
}

Arrays are objects, so you can expect that the for-in loop works for objects too:

var o = {p1: 1, p2: 2};
for (var i in o) {
  console.log(i + '=' + o[i]);
}

This produces:

p1=1

p2=2

There are some details to be aware of:

  • Not all properties show up in a for-in loop. For example, the length (for arrays) and constructor properties will not show up. The properties that do show up are called enumerable. You can check which ones are enumerable with the help of the propertyIsEnumerable() method that everyobject provides.
  • Prototypes that come through the prototype chain will also show up, provided they are enumerable. You can check if a property is an own property versus prototype's using the hasOwnProperty() method.
  • propertyIsEnumerable() will return false for all of the prototype's properties, even those that are enumerable and will show up in thefor-in loop.

Let's see these methods in action. Take this simplified version of Gadget():

function Gadget(name, color) { 
  this.name = name;
  this.color = color;
  this.someMethod = function(){return 1;}
}
Gadget.prototype.price = 100;
Gadget.prototype.rating = 3;

Creating a new object:

var newtoy = new Gadget('webcam', 'black');

Now if you loop using a for-in, you see of the object's all properties, including those that come from the prototype:

for (var prop in newtoy) { 
  console.log(prop + ' = ' + newtoy[prop]);
}

The result also contains the object's methods (as methods are just properties that happen to be functions):

name = webcam

color = black

someMethod = function () { return 1; }

price = 100

rating = 3

If you want to distinguish between the object's own properties versus the prototype's properties, use hasOwnProperty(). Try first:

>>> newtoy.hasOwnProperty('name')

true

>>> newtoy.hasOwnProperty('price')

false

Let's loop again, but showing only own properties:

for (var prop in newtoy) { 
  if (newtoy.hasOwnProperty(prop)) {
   console.log(prop + '=' + newtoy[prop]);
  }
}

The result:

name=webcam

color=black

someMethod=function () { return 1; }

Now let's try propertyIsEnumerable(). This method returns true for own properties that are not built-in:

>>> newtoy.propertyIsEnumerable('name')

true

Most built-in properties and methods are not enumerable:

>>> newtoy.propertyIsEnumerable('constructor')

false

Any properties coming down the prototype chain are not enumerable:

>>> newtoy.propertyIsEnumerable('price')

false

Note, however, that such properties are enumerable if you reach the object contained in the prototype and invoke its propertyIsEnumerable().

>>> newtoy.constructor.prototype.propertyIsEnumerable('price')

true

isPrototypeOf()

Every object also gets the isPrototypeOf() method. This method tells you whether that specific object is used as a prototype of another object.

Let's take a simple object monkey.

var monkey = {   
  hair: true,   
  feeds: 'bananas',   
  breathes: 'air'
};

Now let's create a Human() constructor function and set its prototype property to point to monkey.

function Human(name) {   
  this.name = name;
}
Human.prototype = monkey;

Now if you create a new Human object called george and ask: "Is monkey george's prototype?", you'll get true.

>>> var george = new Human('George'); 
>>> monkey.isPrototypeOf(george)

true

The Secret __proto__ Link

As you know already, the prototype property will be consulted when you try to access a property that does not exist in the current object.

Let's again have an object called monkey and use it as a prototype when creating objects with the Human() constructor.

var monkey = {  
 feeds: 'bananas',  
  breathes: 'air'
};
function Human() {}
Human.prototype = monkey;

Now let's create a developer object and give it some properties:

var developer = new Human();
developer.feeds = 'pizza';
developer.hacks = 'JavaScript';

Now let's consult some of the properties. hacks is a property of thedeveloper object.

>>> developer.hacks

"JavaScript"

feeds could also be found in the object.

>>> developer.feeds

"pizza"

breathes doesn't exist as a property of the developer object, so the prototype is looked up, as if there is a secret link pointing to the prototype object.

>>> developer.breathes

"air"

Can you get from the developer object to the prototype object? Well, you could, using constructor as the middleman, so having something like developer.constructor.prototype should point to monkey. The problem is that this is not very reliable, because constructor is more for informational purposes and can easily be overwritten at any time. You can overwrite it with something that's not even an object and this will not affect the normal functioning of the prototype chain.

Let's set the constructor property to some string:

>>> developer.constructor = 'junk'

"junk"

It seems like the prototype is now all messed up:

>>> typeof developer.constructor.prototype

"undefined"

...but it isn't, because the developer still breathes "air":

>>> developer.breathes

"air"

This shows that the secret link to the prototype still exists. The secret link is exposed in Firefox as the __proto__ property (the word "proto" with two underscores before and two after).

>>> developer.__proto__

Object feeds=bananas breathes=air

You can use this secret property for learning purposes but it's not a good idea to use it in your real scripts, because it does not exist in Internet Explorer, so your scripts won't be portable. For example, let's say you have created a number of objects with monkey as a prototype and now you want to change something in all objects. You can change monkey and all instances will inherit the change:

>>> monkey.test = 1

1

>>> developer.test

1

__proto__ is not the same as prototype. __proto__ is a property of the instances, whereas prototype is a property of the constructor functions.

>>> typeof developer.__proto__

"object"

>>> typeof developer.prototype

"undefined"

Once again, you should use __proto__ only for learning or debugging purposes.

Object-Oriented JavaScript Create scalable, reusable high-quality JavaScript applications and libraries
Published: July 2008
eBook Price: $23.99
Book Price: $39.99
See more
Select your format and quantity:

About the Author :


Stoyan Stefanov

Stoyan Stefanov is a Facebook engineer, author, and speaker. He talks regularly about web development topics at conferences and his blog www.phpied.com, and also runs a number of other sites, including JSPatterns.com—a site dedicated to exploring JavaScript patterns. Previously at Yahoo!, Stoyan was the architect of YSlow 2.0 and creator of the image optimization tool Smush.it.

A "citizen of the world", Stoyan was born and raised in Bulgaria, but is also a Canadian citizen, currently residing in Los Angeles, California. In his offline moments, he enjoys playing the guitar, taking flying lessons, and spending time at the Santa Monica beaches with his family.

Books From Packt

Object-Oriented JavaScript
Object-Oriented JavaScript

Learning jQuery 1.3
Learning jQuery 1.3

Drupal 6 Site Builder Solutions
Drupal 6 Site Builder Solutions

Drupal 6 JavaScript and jQuery
Drupal 6 JavaScript and jQuery

WordPress Plugin Development: Beginner's Guide
WordPress Plugin Development: Beginner's Guide

jQuery UI 1.6: The User Interface Library for jQuery
jQuery UI 1.6: The User Interface Library for jQuery

Spring 2.5 Aspect Oriented Programming
Spring 2.5 Aspect Oriented Programming

Building Powerful and Robust Websites with Drupal 6
Building Powerful and Robust Websites with Drupal 6


 

Your rating: None Average: 4.5 (28 votes)
Great Article by
Thanks man this helped a lot!
Thanks! by
This really helped me with js prototyping, thanks!
very good explanation by
thx for this one
Thanks for a great tut but the second half... by
Thanks for a great tutorial on this topic. I have been going through the codes and like Mithun I also get different outputs. For 'newtoy.constructor' I get 'function Object() { [native code] }' For 'newtoy.constructor.prototype.rating' I get 'undefined' and so on. I used ff4.0. Does anyone know anything about this issue?
Excellent Tutorial. However, by
Excellent Tutorial. However, I faced some problems while executing the code snippets mentioned in the article. NOt sure if I am doind something wrong..... I tested in Firefox 3.6.13 Whenever I do a newtoy.constructor, it prints out Object() in the console log. Also, the prototype property is not accessible using newtoy.constructor.prototype.price printts out undefined. If I treplace newtoy with the word Gadget, thigs seem to print fine. Regards Mithun
Excellent by
It explained the topic very well
Good Stuff! by
Thanks, I Learned a lot!
Great by
Thank's for a comprehensive tutorial!
Thank's by
Very nice indeed! Not much interesting information in the web. But this is one is comprehensive!
Congratulations by
Very good article....

Post new comment

CAPTCHA
This question is for testing whether you are a human visitor and to prevent automated spam submissions.
4
K
N
W
D
d
Enter the code without spaces and pay attention to upper/lower case.
Code Download and Errata
Packt Anytime, Anywhere
Register Books
Print Upgrades
eBook Downloads
Video Support
Contact Us
Awards Voting Nominations Previous Winners
Judges Open Source CMS Hall Of Fame CMS Most Promising Open Source Project Open Source E-Commerce Applications Open Source JavaScript Library Open Source Graphics Software
Resources
Open Source CMS Hall Of Fame CMS Most Promising Open Source Project Open Source E-Commerce Applications Open Source JavaScript Library Open Source Graphics Software