Tuesday, March 19, 2024

Some JavaScript Object Prototyping Patterns

JavaScript developers have several options for creating an Object in JavaScript, from the Object() method to Object literals to constructor functions, there are a lot of ways to get the job done. This article will present a few choice Object creation Patterns that, for the most part, make use of the prototype property to share methods amongst object instances. Pros and cons of each pattern are also listed.

Defining Methods Internally

Of all the ways to create an Object, this is probably the easiest and most intuitive. A function defines the constructor, which sets all of the object’s properties and methods by appending them to the “this” pointer. What you may not realize about this particular pattern is that it’s the most expensive in terms of memory. The reason is that the getInfo() method is recreated for every new object instance…Maybe not so bad if you only need a couple of objects.

function Car(make, model, level, color, warranty) {
    this.make     = make;
    this.model    = model;
    this.level    = level;
    this.color    = color;
    this.warranty = warranty;
   
    this.getInfo = function() {
        return this.make + ', ' + this.model + ', ' + this.level + ', '+ this.color + ', ' + this.warranty;
    };
}

var aCar = new Car('Acura', 'TL', 'Sport', 'blue', 5);
alert(aCar.getInfo());  //displays Acura, TL, Sport, blue, 5

 

Methods Added Externally to the Prototype

There is a way to have all the objects share methods by adding them to the prototype of the constructor function. That requires breaking down the object creation into several steps: the first defines the constructor and properties. Then, each method is appended to the function’s prototype property. The upside here is that you can add methods at any time and they will then be recognized by all objects of that type – even existing instances!

function Car(make, model, level, color, warranty) {
    this.make     = make;
    this.model    = model;
    this.level    = level;
    this.color    = color;
    this.warranty = warranty;
}

Car.prototype.getInfo = function() {
    return this.make + ', ' + this.model + ', ' + this.level + ', '+ this.color + ', ' + this.warranty;
};

var aCar = new Car('Acura', 'TL', 'Sport', 'blue', 5);
alert(aCar.getInfo());  //displays Acura, TL, Sport, blue, 5

Car.prototype.accelerate = function() {
    return 'How fast?';
};
alert(aCar.accelerate()); //displays "How fast?"

 

 

The Prototype Pattern

A slightly more advanced form of the previous example, the Prototype Pattern improves on the method creation by appending them all at once to the prototype within an object literal. Functionally there is no difference between the two models, but this one helps group the methods together:

function Car(make, model, level, color, warranty) {
    this.make     = make;
    this.model    = model;
    this.level    = level;
    this.color    = color;
    this.warranty = warranty;
}

Car.prototype = {
    getInfo: function () {
      return this.make + ', ' + this.model + ', ' + this.level + ', '+ this.color + ', ' + this.warranty;
    }
};

The Revealing Prototype Pattern

This style of Object creation offers a couple of notable benefits over the previous patterns. One notable advantage is that it (once again) encloses both the object’s properties and methods in one construct. Another is that we can now define private object members by creating local variables using the var keyword:

var Car = function(make, model, level, color, warranty) {
    var _make     = make,
        _model    = model,
        _level    = level,
        _color    = color,
        _warranty = warranty;
  
    return {
      getInfo: function () {
        return _make + ', ' + _model + ', ' + _level + ', '+ _color + ', ' + _warranty;
      }
    };
};

Extending the Revealing Prototype Pattern

Yet another benefit of the Revealing Prototype Pattern is that it makes extending and/or overriding existing functionality a little more straightforward. Let’s extend the Car object to create a UsedCar by defining its constructor and then assigning a new Car instance to the UsedCar’s prototype:

var UsedCar = function(mileage) {
    //Define a variable unique to each instance of UsedCar
    this.mileage = mileage;
};

UsedCar.prototype = new Car('Honda', 'Civic', 'LX', 'gray', 2);

Likewise, we can override the Car object’s functionality simply by replacing it with another function of the same name. However, it might benefit the UsedCar to reuse the existing getInfo() method by extending it. WE can obtain the Car’s getInfo() method from the UsedCar’s prototype because we stored a Car instance there. Using a closure, we can append the UsedCar’s mileage to the output of the Car’s getInfo() method output:

var UsedCar = function(mileage) {
    //Define a variable unique to each instance of UsedCar
    this.mileage = mileage;
};

UsedCar.prototype = new Car('Honda', 'Civic', 'LX', 'gray', 2);
var aUsedCar = new UsedCar(50000);
alert(aUsedCar.getInfo()); //displays Honda, Civic, LX, gray, 2

//this will add the mileage to getInfo()'s output
UsedCar.prototype.getInfo = function(superGetInfo) {
  return function() { return superGetInfo() + ', '+ this.mileage; };
}(UsedCar.prototype.getInfo);

alert(aUsedCar.getInfo()); //displays Honda, Civic, LX, gray, 2, 50000

 


Conclusion

That concludes our look at the most common Object Prototyping Patterns in JavaScript. Maybe there were a couple more than you thought? In the next article, we’re going to look at a way to abstract them by creating a Prototype Wrapper function. That’s bound to be a lot of fun!

 

 

If you enjoyed this article, please contribute to Rob’s less lucrative music career by purchasing one of Rob’s cover or original songs from iTunes.com for only 0.99 cents each.

Rob Gravelle resides in Ottawa, Canada, and is the founder of GravelleConsulting.com. Rob has built systems for Intelligence-related organizations such as Canada Border Services, CSIS as well as for numerous commercial businesses. Email Rob to receive a free estimate on your software project. Should you hire Rob and his firm, you’ll receive 15% off for mentioning that you heard about it here!

 

In his spare time, Rob has become an accomplished guitar player, and has released several CDs. His former band, Ivory Knight, was rated as one Canada’s top hard rock and metal groups by Brave Words magazine (issue #92).

Rob uses and recommends MochaHost, which provides Web Hosting at $3.10 per month, 2 LifeTime Free Domains, and 6 Months Free!

Rob Gravelle
Rob Gravelle
Rob Gravelle resides in Ottawa, Canada, and has been an IT guru for over 20 years. In that time, Rob has built systems for intelligence-related organizations such as Canada Border Services and various commercial businesses. In his spare time, Rob has become an accomplished music artist with several CDs and digital releases to his credit.

Get the Free Newsletter!

Subscribe to Developer Insider for top news, trends & analysis

Popular Articles

Featured