Functional vs. Object-Oriented JavaScript Development

0

Category :

JavaScript is such a flexible language that it can be used to write code that follows two radically different programming paradigms—functional programming and object-oriented programming (OOP).

Natively, the JavaScript language allows you to treat functions in just the same fashion as values. You can assign a function to a variable and also pass it around to other functions. Abstractly speaking, we can say that a JavaScript function is a value of a very special type: the value is the behavior provided and the type is something we can just call “function.”

Natively, the JavaScript language also offers objects. In JavaScript, objects are seen as plain bags of properties and methods. They look more like simple dictionaries of data and behavior than fully-fledged objects as you will find in a qualified OOP language such as C#, Java, or C++. In classic OOP, a class represents the layout of what will actually become an object once an instance of that class is created through the new operator. In JavaScript, you have no classes that provide the blueprints for objects to create. In JavaScript, the “blueprint” for an object is an implicit concept and it looks a lot like a dictionary. So in JavaScript, you just create objects and store data into them. JavaScript objects, however, offer some degree of object-oriented capabilities such as encapsulation and inheritance.

For once, the quick answer to the question that this article addresses is not the classic “It depends.” It is, instead, a less compromising “whatever you ultimately like most”. But let’s elaborate a bit on it.

Functional Programming in Brief

In functional programming the building block of code is the “function”, as opposed to the class in object-oriented programming and the subroutine in procedural programming. A function is a unit of code that only describes the operations to be performed on the input. A function gets some input and returns some output; everything else is hidden from view.

As a functional programmer, you build your applications by pipelining function calls to create a super function that just gets the program’s input and returns the program’s output. There’s typically no layer where you process the input, store state, arrange a sequence of statements, update the state, and decide about the next step. A function is a like a value and can be used as an argument and be passed to other functions as well as used in any other context where values can be used.

Note, though, that real-world functional languages such as F# also mix concepts like functions and pipelining with variables and some simple notion of state. F#, for example, lets you store intermediate results in some local variable and use it as the input for successive function calls. The scope of such variables though is fairly limited and there’s anything like global or static members.

JavaScript and Functional Programming

JavaScript is not a truly functional language such as F#. JavaScript, however, does support some constructs that are typical of a functional language. By using these constructs extensively, you can do good functional programming in JavaScript. At the end of the day, this is largely what you do when you use the jQuery library.

In JavaScript, anonymous functions are the pillar of functional programming. An anonymous function is a direct offshoot of lambda calculus or, if you like it most, a language adaptation of old-fashioned function pointers.

The only difference between a regular function and an anonymous function is in the name. In a functional context, you don’t strictly need to name a function especially if you’re using it as a value that you pass around. Here’s an example that shows how to combine together various functions.

// Function to calculate a total
var CalcTotal = function(x, y) {
   return x + y;
};
 
// Function to add taxes
var AddTaxes = function(x) {
  return x * 1.2;
};
 
// Function that pipelines the other two
var CalcTotalPlusTaxes = function (fnCalcTotal, fnAddTaxes, x, y) {
    return fnAddTaxes(fnCalcTotal(x, y)); 
};
 
// Execution
var result = CalcTotalPlusTaxes(CalcTotal, AddTaxes, 40, 60);
alert(result);

Treating anonymous functions as plain values allows you to mix data and behavior in a quite effective way. This gives you a chance to apply some design principles to JavaScript code such as Dependency Inversion. When a higher level module (whether an object or a function) depends on capabilities provided by lower level modules, you can just inject the expected behavior as an argument. In many cases, this approach augments the readability and elegance of the code; for sure, it gives you more power to deal with complexity.

jQuery and the Consecration of Functional Programming

The jQuery library called more than ever the people’s attention on functional programming. The jQuery library is based on the jquery object or $. The $ is essentially a wrapper around DOM elements and DOM elements can be passed into the object through the type constructor—the popular $(…) expression. Furthermore, jQuery allows call chaining meaning that the $ object can pass its own wrapped values into other functions that return the same $ object.

These three facts about jQuery qualify the root object of the library as a monad; and monads are a fundamental concept in the theory of functional languages. jQuery takes you to reason in terms of chunks of behavior that you concatenate and pass around. This is extremely effective as long as the values you ultimately work with are just those that library manipulates natively. The jQuery library is effective because it allows you to enjoy the power (and to some extent the cleanness) of functional programming for the Web environment where all you do is manipulation of wrapped DOM elements.

You may be a huge fan of the jQuery library and appreciate the functional lifestyle it pushes. However, that has to be put into perspective and should not become a reason to push the functional programming paradigm over everything else. Let’s have a look at the following snippet from the source code of jQuery.

jQuery.fn = jQuery.prototype = {
    init: function( selector, context ) { ... },
       size: function() { return this.length; },
       each: function( callback, args ) {
        return jQuery.each( this, callback, args );  },
       ready: function( fn ) { ... }
       :
}

As you can see, the jQuery object has its own prototype featuring capabilities such as size and each. More interestingly, when you write a jQuery plugin you just extend the basic prototype adding a new function. At the end of the day, effective JavaScript programming is always a mix of functional and object-oriented style. With jQuery, though, you are mostly exposed to the functional part of it.

Objects in JavaScript

There’s a significant difference between objects in a qualified OOP language and JavaScript. In OOP languages, the class is a blueprint for actual objects you use. In JavaScript, you just have objects whose blueprint is that of a dictionary of data and functions. When you create a new object in JavaScript, you have an empty dictionary you can fill with anything you like.

Having said that, with a bit of work you can create (and reuse) custom objects and manage for them to inherit from existing objects and also behave polymorphically. This work is just what JavaScript object-oriented libraries do.

When it comes to adding layers to JavaScript to make it closer to a qualified OOP language and gain some more programming power and code reusability, you have to choose from two main approaches for extending the capabilities of the native JavaScript objects: closures and prototypes.

Before we get to that, however, a few words about the native Object type in JavaScript and it usage.

You can use the new keyword to create a new dictionary-like object in JavaScript. Next, you stuff data into it and you can add methods by wiring functions to property names. Here’s an example:

var person = new Object();
 person.Name = "Dino";
 person.LastName = "Esposito";
 person.BirthDate = new Date(1979,10,17)
 person.getAge = function() {
 var today = new Date();
 var thisDay = today.getDate();
 var thisMonth = today.getMonth();
 var thisYear = today.getFullYear();
 var age = thisYear-this.BirthDate.getFullYear()-1;
 if (thisMonth > this.BirthDate.getMonth())
   age = age +1;
 else 
 if (thisMonth == this.BirthDate.getMonth() &&
   thisDay >= this.BirthDate.getDate())
   age = age +1;
 return age;
}

What we have is an object modeled after a person; we don’t have a Person object. A possible way to define the layout of a type is creating a new, all-encompassing function that exposes just the members we like. In addition, in JavaScript all intrinsic objects have a read-only property named prototype. You can use the prototype property to provide a base set of functionality shared by any new instance of an object of that type. These two are the mechanisms to leverage for OOP in JavaScript.

Object-orientation through Closures

A closure is a general concept of programming languages. Applied to JavaScript, a closure is a function that can have variables and methods defined together within the same context. In this way, the outermost (anonymous or named) function “closes” the expression. Here’s an example of the closure model for a function that represents a Person type:

var Person = function(name, lastname, birthdate) 
{
   this.Name = name;
   this.LastName = lastname;
   this.BirthDate = birthdate;
 
   this.getAge = function() {
      var today = new Date();
      var thisDay = today.getDate();
      var thisMonth = today.getMonth();
      var thisYear = today.getFullYear();
      var age = thisYear-this.BirthDate.getFullYear()-1;
      if (thisMonth > this.BirthDate.getMonth())
          age = age +1;
      else 
         if (thisMonth == this.BirthDate.getMonth() &&
             thisDay >= this.BirthDate.getDate())
             age = age +1;
      return age;
   }
}

As you can see, the closure is nothing more than the constructor of the pseudo-class. In a closure model, the constructor contains the member declarations and members are truly encapsulated and private to the class. In addition, members are instance based, which increases the memory used by the class. Here’s how you use the object:

var p = new Person("Dino", "Esposito", new Date( ... );
alert(p.Name + " is " + p.getAge());

The closure model gives full encapsulation, but nothing more. To compose objects, you can only resort to aggregation.

Object-orientation through Prototypes

The prototype model entails that you define the public structure of the class through the JavaScript prototype object. The following code sample shows how to rewrite the preceding Person class to avoid a closure.

// Pseudo constructor
var Person = function(name, lastname, birthdate)
{
  if(name && lastname && birthdate) {
   this.initialize(name, lastname, birthdate);
  }
}
// Members
Person.prototype.initialize = function(name, lastname, birthdate)
{

 this.Name = name;
 this.LastName = lastname;
 this.BirthDate = birthdate;
}

Person.prototype.getAge = function()   
{
 var today = new Date();
 var thisDay = today.getDate();
 var thisMonth = today.getMonth();
 var thisYear = today.getFullYear();
 var age = thisYear-this.BirthDate.getFullYear()-1;
 if (thisMonth > this.BirthDate.getMonth())
  age = age +1;
 else 
    if (thisMonth == this.BirthDate.getMonth() &&
     thisDay >= this.BirthDate.getDate())
     age = age +1;
 return age;
}

In the prototype model, the constructor and members are clearly separated and a constructor is always required. As for private members, you just don’t have them. The var keyword which would keep them local in a closure doesn’t apply in the prototype model. So you can define getter/setter for what you intend to be properties, but the backing field will anyway remain accessible from the outside. You can resort to some internal (and documented) convention such as prefixing with an underscore the name of members you intend as private. It’s just a convention, however.

By using the prototype feature you can achieve inheritance by simply setting the prototype of a derived object to an instance of the “parent” object.

Developer = function Developer(name, lastname, birthdate) 
{ 
   this.initialize(name, lastname, birthdate);
}
Developer.prototype = new Person();

Note that you always need to use this to refer to members of the prototype from within any related member function.

Closure vs. Prototype

In the prototype model, members are shared by all instances as they are invoked on the shared prototype object. In this way, the amount of memory used by each instance is reduced which would also provide for faster object instantiation. Aside from syntax peculiarities, the prototype model makes defining classes much more similar to the classic OOP model than the closure model.

The choice between closure and prototype should also be guided by performance considerations and browser capabilities. Prototypes have a good load time in all browsers; and indeed, they have excellent performance in Firefox. (In contrast, closures have a better load time than prototypes in Internet Explorer.) Prototypes provide better support for IntelliSense, and allow for tool-based statement completion when used in tools that support this feature, such as Visual Studio. Prototypes can also help you obtain type information by simply using reflection. You won’t have to create an instance of the type in order to query for type information, which is unavoidable if closures are used. Finally, prototypes allow you to easily view private class members when debugging. Debugging objects derived using the closure model requires a number of additional steps.

As an example, consider that the Microsoft AJAX library is built using the prototype model (and the closure model was discarded along the way).


Conclusion

JavaScript is neither 100% functional or object-oriented. However, it lends itself to support to a good extent both paradigms, because in a way it borrows concepts from both qualified functional and object-oriented languages. This inevitably creates some noise around the programming techniques you can employ. As a developer, you must be ready to accept compromises that may not be acceptable in a fully-qualified functional or object-oriented scenario.

JavaScript is a must today for writing client-side code for Web and mobile applications. And the client-side code we are called to write is no longer plain scripting of the document object model as it was when the language was introduced. Today, we often use JavaScript for some client-side logic and input validation. To make the whole development process more sustainable, we resort to JavaScript libraries that abstract through functions or classes some of the most common tasks. The jQuery library is just the most illustrious example.

Because of the success of the jQuery library, functional programming is probably gaining momentum and overcoming object-oriented programming in JavaScript. But in the end, the final decision is left to you and attitude, skills, and ease are the key parameters for a decision. You don’t have to take it as a matter of religion and pick up option and stick to that forever. To use JavaScript at its best, you probably have to mix functional features with OO features.

Having said that, if I have to write client code for a Web front-end, I’d probably go with jQuery, use a lot of anonymous functions and don’t even bother about custom objects. Instead, if I have to write my own framework to support some server-side infrastructure, well, I’d probably opt for an object-oriented approach and consider closures or prototypes.

my thanks to:
http://msdn.microsoft.com/en-us/scriptjunkie/gg476048.aspx

0 comments:

Post a Comment