Thursday, November 14, 2024

The Classy Way to Create JavaScript Objects

I think that it’s fair to say that most people would rather create JS objects using a wrapper of some type than from scratch. That’s why pretty much every JS library includes some object creation functionality. In fact, now there are even a few libraries that specialize in nothing but objects. Today, I’d like to tell you about one I came across called Classy. It’s is a small JS library that implements Python-inspired classes for JavaScript.

Classy vs. Prototype

The Classy library is not altogether a new way to create classes in JavaScript. Far from it. Classy draws liberally from other JS libraries, including Prototype and base2. Both of these are regarded as two of the strongest in the area of object creation, so you could say that Classy chose its parents wisely! Note the similarities between Prototype and Classy in the following side-by-side comparison:

        Prototype                                    Classy --  --  --  --  --  --  --  --  --  --  --  --  --  --  --  --  --  --  --  --  --  --  --  --  --  --  --  --  --  --  --  --  --  --  --  --  --  --  --      
var Animal = Class.create({                 var Animal = Class.$extend({
  initialize: function(name, age) {           __init__ : function(name, age) {
    this.name = name;                           this.name = name;
    this.age = age;                             this.age = age;
    this.health = 100;                          this.health = 100;                           
  },                                          },
  die : function() {                          die: function() {
    this.health = 0;                            this.health = 0;
  },                                          },
  eat : function(what) {                      eat: function(what) {
    this.health += 5;                           this.health += 5;
  }                                           }
});                                        });

Extending Objects

Classy implements object subclassing via the extend() method. While Prototype does not employ the extend() method, base2 does use it in a way which very closely resembles Classy, which leads me to conclude that base2 was probably the inspiration here:

          base2                                      Classy --  --  --  --  --  --  --  --  --  --  --  --  --  --  --  --  --  --  --  --  --  --  --  --  --  --  --  --  --  --  --  --  --  --  --  --  --  --  -- 
var Tiger = Animal.extend({                var Tiger = Animal.$extend({
  initialize: function(name, age) {          __init__ : function(name, age) {        
    // call the "super" method                 // call the "super" method        
    this.base();                               this.$super(name, age);                
  },                                         },
  eat: function(animal) {                    eat: function(animal) {
    this.base();                               this.$super(animal);
    animal.die();                              animal.die();
  }                                          }
});                                        });

Nonetheless, there are some differences between the base2 and Classy implementation of the extend() method. The base2 library utilizes the base() method to call the superclass’s method of the same name – and magically, without the need to pass arguments! The Classy library, on the other hand, employs the familiar Java $super method to accomplish the same thing. Note that the dollar sign ($) is required because “super” is a reserved word in JavaScript.

Adding Class-level Attributes

Classes may contain a special attribute called “__classvars__” that defined a collection of class-level attributes. This is a great place to define constants and other read-only data.

var MyClass = Class.$extend({
    __classvars__ : {
      MAX_ITEMS : 10
    }
});
alert(MyClass.MAX_ITEMS);  //displays 10

To access these attributes from within an instance, use the $class attribute. It’s the class object for “this” instance and is useful to access class attributes from an object instance:

    
alert(MyClass().$class.MAX_ITEMS);

ClassyJS Features

Now what would be the point of creating a new JS object wrapper library if it didn’t include some new functionality? Here are some of the highlights:

As of version 1.1 (the current version is 1.4), the Class.$withData(data) method can be used to create a new instance of a class which bypasses the constructor and assigns the attributes from the given object. In other words, both the names and properties of the passed object are added to the base object.

var MyClass = Class.$extend({
  __init__ : function() { 
    this.prop1 = 'a string';
    this.prop2 = 23;
  },
  toString() : function() {
    return this.prop1 + ', ' + this.prop2;
  })
});
var obj = MyClass.$withData({secretOfLife: 42});
alert(obj.secretOfLife); //displays 42
alert(obj) //displays undefined, undefined

Since the constructor is not called, the prop1 and prop2 attributes are never defined. Nonetheless, you still have access to the class methods as well as your provided attributes.

Class.$noConflict() allows us to use multiple versions of Classy side by side or in combination with other libraries where naming conflicts might occur. It solves the problem by removing the Class object from the window object, thus restoring it to its previous state before Classy was loaded. It then returns the class object from the function:

(function(Class) {
  // The Classy Class object will only be available within this function
})(Class.$noConflict());

 

Conclusion

Having written about wrapping prototypal inheritance to make it more OO-like, I can tell you that it isn’t easy. There are a lot of gotchas to contend with. That’s why using a library like Classy is significantly preferable to writing your own. Whether or not you decide to go with Classy or not is entirely up to you. There is some element of personal preference at involved when chosing any JS library, depending on your coding style and familiarity with other languages like Python and Java.

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