Class-less Objects 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 | October 2008 | AJAX Web Development

Java and JavaScript are very different languages, although the similarity in the names and the similar C-like syntax can confuse people sometimes. In this article by Stoyan Stefanov, let's take a look at one pretty major difference - how objects are created. In Java, you have classes. Then objects, a.k.a. instances, are created based on those classes. In JavaScript, there are no classes and objects are more like hash tables of key-value pairs. Then what about inheritance? OK, one step at a time.

JavaScript Objects

When you think about a JavaScript object, think a hash. That's all there is to objects - they are just collections of name-value pairs, where the values can be anything including other objects and functions. When an object's property is a function, you can also call it a method.

This is an empty object:

var myobj = {};

Now you can start adding some meaningful functionality to this object:

myobj.name = "My precious";
myobj.getName = function() {return this.name};

Note a few things here:

  • this inside a method refers to the current object, as expected
  • you can add/tweak/remove properties at any time, not only during creation

Another way to create an object and add properties/methods to it at the same time, is like this:

var another = {
name: 'My other precious',
getName: function() {
return this.name;
}
};

This syntax is the so-called object literal notation - you wrap everything in curly braces { and } and separate the properties inside the object with a comma. Key:value pairs are separated by colons. This syntax is not the only way to create objects though.

Constructor Functions

Another way to create a JavaScript object is by using a constructor function. Here's an example of a constructor function:

function ShinyObject(name) {
this.name = name;
this.getName = function() {
return this.name;
}
}

Now creating an object is much more Java-like:

var my = new ShinyObject('ring');
var myname = my.getName(); // "ring"

There is no difference in the syntax for creating a constructor function as opposed to any other function, the difference is in the usage. If you invoke a function with new, it creates and returns an object and, via this, you have access to modifying the object before you return it. By convention though, constructor functions are named with a capital letter to distinguish visually from normal functions and methods.

So which way is better - object literal or constructor function? Well, that depends on your specific task. For example, if you need to create many different, yet similar objects, then the class-like constructors may be the right choice. But if your object is more of a one-off singleton, then object literal is definitely simpler and shorter.

OK then, so since there are no classes, how about inheritance? Before we get there, here comes a little surprise - in JavaScript, functions are actually objects.

(Actually in JavaScript pretty much everything is an object, with the exception of the few primitive data types - string, boolean, number and undefined. Functions are objects, arrays are objects, even null is an object. Furthermore, the primitive data types can also be converted and used as objects, so for example "string".length is valid.)

Function Objects and Prototype Property

In JavaScript, functions are objects. They can be assigned to variables, you can add properties and methods to them and so on. Here's an example of a function:

var myfunc = function(param) {
alert(param);
};

This is pretty much the same as:

function myfunc(param) {
alertparam);
}

No matter how you create the function, you end up with a myfunc object and you can access its properties and methods.

alert(myfunc.length);     // alerts 1, the number of parameters
alert(myfunc.toString()); // alerts the source code of the function

One of the interesting properties that every function object has is the prototype property. As soon as you create a function, it automatically gets a prototype property which points to an empty object. Of course, you can modify the properties of that empty object.

alert(typeof myfunc.prototype); // alerts "object"
myfunc.prototype.test = 1; // completely OK to do so

The question is, how is this prototype thing useful? It's used only when you invoke a function as a constructor to create objects. When you do so, the objects automatically get a secret link to the prototype's properties and can access them as their own properties. Confusing? Let's see an example.

A new function:

function ShinyObject(name) {
this.name = name;
}

Augmenting the prototype property of the function with some functionality:

ShinyObject.prototype.getName = function() {
return this.name;
};

Using the function as a constructor function to create an object:

var iphone = new ShinyObject('my precious');
iphone.getName(); // returns "my precious"

As you can see the new objects automatically get access to the prototype's properties. And when something is getting functionality "for free", this starts to smell like code reusability and inheritance.

 


Inheritance via Prototype

Now let's see how you can use the prototype to implement inheritance.

Here's a constructor function which will be the parent:

function NormalObject() {
this.name = 'normal';
this.getName = function() {
return this.name;
};
}

Now a second constructor:

function PreciousObject(){
this.shiny = true;
this.round = true;
}

Now the inheritance part:

PreciousObject.prototype = new NormalObject();

Voila! Now you can create precious objects and they'll get all the functionality of the normal objects:

var crystal_ball = new PreciousObject();
crystal_ball.name = 'Ball, Crystal Ball.';
alert(crystal_ball.round); // true
alert(crystal_ball.getName()); // "Ball, Crystal Ball."

Notice how we needed to create an object with new and assign it to the prototype, because the prototype is just an object. It's not like one constructor function inherited from another, in essence we inherited from an object. JavaScript doesn't have classes that inherit from other classes, here objects inherit from other objects.

If you have several constructor functions that will inherit NormalObject objects, you may create new NormalObject() every time, but it's not necessary. Even the whole NormalObject constructor may not be needed. Another way to do the same would be to create one (singleton) normal object and use it as a base for the other objects.

var normal = {
name: 'normal',
getName: function() {
return this.name;
}
};

Then the PreciousObject can inherit like this:

PreciousObject.prototype = normal;

Inheritance by Copying Properties

Since inheritance is all about reusing code, yet another way to implement it is to simply copy properties.

Imagine you have these objects:

var shiny = {
shiny: true,
round: true
};


var normal = {
name: 'name me',
getName: function() {
return this.name;
}
};

How can shiny get normal's properties? Here's a simple extend() function that loops through and copies properties:

function extend(parent, child) {
for (var i in parent) {
child[i] = parent[i];
}
}

extend(normal, shiny); // inherit
shiny.getName(); // "name me"

Now this property copying may look like overhead and not performing too well, but truth is, for many tasks it's just fine. You can also see that this is an easy way to implement mixins and multiple inheritance.

Crockford's beget Object

Douglas Crockford, a JavaScript guru and creator of JSON, suggests this interesting begetObject() way of implementing inheritance:

function begetObject(o) {
function F() {}
F.prototype = o;
return new F();
}

Here you create a temp constructor so you can use the prototype functionality, the idea is that you create a new object, but instead of starting fresh, you inherit some functionality from another, already existing, object.

Parent object:

var normal = {
name: 'name me',
getName: function() {
return this.name;
}
};

A new object inheriting from the parent:

var shiny = begetObject(normal);

Augment the new object with more functionality:

shiny.round = true;
shiny.preciousness = true;

YUI's extend()

Let's wrap up with yet another way to implement inheritance, which is probably the closest to Java, because in this method, it looks like a constructor function inherits from another constructor function, hence it looks a bit like a class inheriting from a class.

This method is used in the popular YUI JavaScript library (Yahoo! User Interface) and here's a little simplified version:

function extend(Child, Parent) {
var F = function(){};
F.prototype = Parent.prototype;
Child.prototype = new F();
}

With this method you pass two constructor functions and the first (the child) gets all the properties and methods of the second (the parent) via the prototype property.

Summary

Let's quickly summarize what we just learned about JavaScript:

  • there are no classes
  • objects inherit from objects
  • object literal notation var o = {};
  • constructor functions provide Java-like syntax var o = new Object();
  • functions are objects
  • all function objects have a prototype property
  • And finally, there are dozens of ways to implement inheritance, you can pick and choose depending on your task at hand, personal preferences, team preferences, mood or the current phase of the Moon.

 

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

Drupal 6 JavaScript and jQuery: RAW
Drupal 6 JavaScript and jQuery: RAW

Object-Oriented JavaScript
Object-Oriented JavaScript

Learning the Yahoo! User Interface library
Learning the Yahoo! User Interface library

Learning jQuery 1.3
Learning jQuery 1.3

jQuery Reference Guide
jQuery Reference Guide

Learning Dojo
Learning Dojo

Apache Struts 2 Web Application Development
Apache Struts 2 Web Application Development

DWR Java AJAX Applications
DWR Java AJAX Applications

 


No votes yet
web host plan by
Hi there, You have accomplished an incredible job. I will undoubtedly digg it and personally suggest to my buddies. I'm certain they are going to be benefited from this site.

Post new comment

CAPTCHA
This question is for testing whether you are a human visitor and to prevent automated spam submissions.
Y
3
R
G
c
r
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