http://www.developer.com/lang/jscript/javascript-prototype-object-and-inheritance.html

Back to article

Object-Oriented JavaScript Demystified


June 8, 2011

For the first time in my career, I'm spending the majority of most days working with a programming language other than PHP. That language is JavaScript, and much to my surprise, I'm quite enjoying it. Most developers tend to pick up JavaScript with a fair amount of trepidation, perhaps more than any other reason because the language has suffered from a pervasive amount of misinformation and FUD almost since its inception. In fact, legend has it that the language's very name was contrived by its creators in the hopes that a language titled "JavaScript" could capture the attention of developers flocking to Java, which had been released only months prior.

One common misperception is the language's inability to create "proper" applications because it isn't object-oriented. To paraphrase a common saying, "just because it doesn't look like a duck nor quack like a duck doesn't mean it isn't a duck." JavaScript is object-oriented. But JavaScript's particular form of object-orientation doesn't look much like that used in Java, Ruby or PHP because it is prototype-based, requiring developers to use a rather different set of syntax which looks little like traditional OOP.

Given all the confusion, I thought it would be useful to offer a quick introduction to JavaScript's admittedly exotic object-oriented syntax. This knowledge will prove crucial when exploring today's cutting-edge JavaScript-based technologies such as Node.js and Backbone.

Creating a Class

Most object-oriented languages support class creation using a class statement. JavaScript does not support the concept of a class in its strictest definition, but rather supports containers which aggregate class methods and properties (although these containers are often referred to as classes for sake of convenience, which I will do throughout the remainder of this article). These classes are created via a constructor function, which as you can see, looks like any other standard JavaScript function:

function POI() {
  alert("New point of interest");
}

Once defined you can instantiate the class using the new statement:

var museum = new POI();

After making the above call, the message found in the constructor's alert() statement will be displayed.

Class Properties and Methods

JavaScript supports both properties and methods. For instance, the following revised POI constructor will define and set three public properties, title, latitude, and longitude:

function POI(title, latitude, longitude) {
  this.title = title;
  this.latitude = latitude;
  this.longitude = longitude;
}

Because these properties are public, you can refer to them outside of the constructor, like this:

var museum = new POI("Former Soviet Embassy", "38.9044838", "-77.0360489");

alert(museum.latitude);

This syntax may lead you to conclude that methods too should be defined within the constructor. For instance, suppose you wanted to create a class method which determined which hemisphere the point of interest resided in based on its coordinates. While this calculation is easily accomplished by determining whether latitude is positive or negative, one could certainly imagine much more complex location-related methods:

function POI(title, latitude, longitude) {
  this.title = title;
  this.latitude = latitude;
  this.longitude = longitude;
  this.hemisphere = function() { 
    if (this.latitude < 0) { 
      return "Southern";
    } else {
      return "Northern";
    }
  };
}

Once defined, you can call the method like this:

var museum = new POI("Former Soviet Embassy", "38.9044838", "-77.0360489");
var hemisphere = museum.hemisphere();

In this example, hemisphere is set to "Northern," which is precisely what we would expect. So what's the problem with this approach? When a method is defined within the constructor, this method definition will be copied into memory every time a new POI object is constructed. If you're building a large location-based application, it's conceivable that you could be simultaneously working with hundreds or even thousands of POI objects, making this an inefficient approach. The proper approach involves using the prototype object, which I'll introduce next.

The JavaScript Prototype Object

All JavaScript objects are associated with an internal reference to another object known as the prototype. Whenever a new custom object is created, any properties and methods defined within the prototype are automatically inherited by the custom object (as opposed to those properties and methods being repeatedly redefined), thereby reducing the amount of memory required to hold an object in memory. Therefore the proper way to define the hemisphere() method follows:

function POI(title, latitude, longitude) {
  this.title = title;
  this.latitude = latitude;
  this.longitude = longitude;
}

POI.prototype.hemisphere = function() { 
  if (this.latitude < 0) { 
    return "Southern";
  } else {
    return "Northern";
  }
};

var museum = new POI("Former Soviet Embassy", "38.9044838", "-77.0360489");

var hemisphere = museum.hemisphere();

You might be wondering why properties aren't defined in this fashion. As a matter of fact, they can be:

function POI(title, latitude, longitude) {
  this.title = title;
  this.latitude = latitude;
  this.longitude = longitude;
}

POI.prototype.title = 'Default title';
POI.prototype.latitude = 'Default latitude';
POI.prototype.longitude = 'Default longitude';

JavaScript and Inheritance

The prototype-based approach also lends itself nicely to inheritance. The following example presents a simplified version of the POI class, which is inherited by the Museum class. Notice in particular how the Museum's prototype property is assigned the POI's constructor:

function POI() {
}

POI.prototype.title = 'Default title';

POI.prototype.setTitle = function(title) { 
  this.title = title;
};

function Museum() {
  POI.call(this);
}

Museum.prototype = new POI();

var smithsonian = new Museum();

smithsonian.setTitle('Smithsonian Air and Space Museum');

alert(smithsonian.title);

Further Reading

Quite a bit has been written about JavaScript's object-oriented capabilities; unfortunately much of it is misleading or downright incorrect, therefore be sure to follow up on anything you learn online, particularly when the information hails from older blog posts. I highly recommend reading these three resources to learn more about JavaScript's many misunderstandings:

About the Author

Jason Gilmore -- Contributing Editor, PHP -- is the founder of EasyPHPWebsites.com, and author of the popular book, "Easy PHP Websites with the Zend Framework". Jason is a cofounder and speaker chair of CodeMash, a nonprofit organization tasked with hosting an annual namesake developer's conference, and was a member of the 2008 MySQL Conference speaker selection board.

Sitemap | Contact Us