Thursday, October 1, 2015

Augmenting Types in Javascript

In today's post, I will be discussing the advantages of augmenting types and how to accomplish that in Javascript.

Augmenting Object

Augmenting is the mechanism of extending characteristics of a thing by adding new things. That characteristic is then available to all the instances of that thing.
So in case of an object, by adding a method or property to Object's prototype, we make it available to all objects.

For example,

var person = {

   "FirstName" : "Abhi",

   "LastName": "Jain"

}

console.log(person.FirstName);

console.log(person.email);            //undefined

As you can see in the example, the email property was not available for the person object. By adding email to Object's prototype, we make it available to all objects. This is called augmenting the Object.prototype.

Object.prototype.email= "xyz";

console.log(person.email);           //xyz 

Similarly, we can augment Object.prototype to add new methods which will become available to all the objects. 

Augmenting Types

In the same way, we can augment functions, booleans, arrays, strings, numbers and regular expressions. This can come in handy, when we need to implement some functionality to be used across the board. For example, we can add integer function to Number to return the integer part of the number. We can do it like this:

Number.prototype.integer = function(){

      return Math[this < 0 ? 'ceil' : 'floor'](this);

}

console.log((-11 / 3).integer());

Similarly, we can add trim method to String which will simply remove the extra spaces.

String.prototype.trim = function(){

     return this.replace(/^\s+|\s+$/g, '');

}

console.log("  Abhi  ".trim());       //"Abhi"

Now the trim method will be available for all strings.

Caveat

Modifying Object.prototype (and others like Number.prototype, etc) is usually considered evil and frowned upon. The reason being namespace collision. Suppose, one library adds Map method to Object with some implementation and another library also adds Map method with another implementation, so the latter one overrides the former one. This might lead to broken functionality and hard to maintain code.

Another problem is that for-in statement interacts badly with prototypes. When we do a for in loop like this: 

for (var key in person)

{

     console.log(key);   

}

we get FirstName, LastName and Email. Although Email is not person object's own property, it still pops up in the loop. One way to mitigate this is to use hasOwnProperty like this:

for (var key in person)
{

    if(person.hasOwnProperty(key))

    {

        console.log(key);

    }

} 

This will show only FirstName and LastName.

Conclusion

In this post, we saw one of the powerful features of Javascript on how to augment types and how it can be useful to us. We can use this feature to help us add generic functionality which might be needed at multiple places. Some of these things are not that relevant anymore as there are lots of Javascript libraries which give us most of the functionalities we need. However, if we need something custom for ourselves these can come in handy.
Also, such native augmentation should be used when you know that you are working in a controlled environment.

Ref: Javascript - The Good Parts by Douglas Crockford

For future updates to my weekly blog, please subscribe to my blog via the "Subscribe To Weekly Post" feature at the right and follow me on Twitter. Until then Happy Coding :)

No comments:

Post a Comment