Functional programming

While imperative code tells the machine, step-by-step, what it needs to do to solve the problem, functional programming instead seeks to describe the problem mathematically so that the machine can do the rest.

With a more functional approach, the same application can be written as follows:

// separate the data and logic from the interface
var printPrice = function(price, label) {
  var node = document.createElement("li");
  var textnode = document.createTextNode(label+' price: $'+price);
  node.appendChild(textnode);
  document.getElementById('products 2').appendChild(node);
}

// create function objects for each type of coffee
var columbian = function(){
  this.name = 'columbian'; 
  this.basePrice = 5;
};
var frenchRoast = function(){
  this.name = 'french roast'; 
  this.basePrice = 8;
};
var decaf = function(){
  this.name = 'decaf'; 
  this.basePrice = 6;
};

// create object literals for the different sizes
var small = {
  getPrice: function(){return this.basePrice + 2},
  getLabel: function(){return this.name + ' small'}
};
var medium = {
  getPrice: function(){return this.basePrice + 4},
  getLabel: function(){return this.name + ' medium'}
};
var large = {
  getPrice: function(){return this.basePrice + 6},
  getLabel: function(){return this.name + ' large'}
};

// put all the coffee types and sizes into arrays
var coffeeTypes = [columbian, frenchRoast, decaf];
var coffeeSizes = [small, medium, large];

// build new objects that are combinations of the above
// and put them into a new array
var coffees = coffeeTypes.reduce(function(previous, current) {
  var newCoffee = coffeeSizes.map(function(mixin) {
    // `plusmix` function for functional mixins, see Ch.7
    var newCoffeeObj = plusMixin(current, mixin);
    return new newCoffeeObj();
  });
  return previous.concat(newCoffee);
},[]);

// we've now defined how to get the price and label for each
// coffee type and size combination, now we can just print them
coffees.forEach(function(coffee){
  printPrice(coffee.getPrice(),coffee.getLabel());
});

The first thing that should be obvious is that it is much more modular. This makes adding a new size or a new coffee type as simple as shown in the following code snippet:

var peruvian = function(){
  this.name = 'peruvian'; 
  this.basePrice = 11;
};

var extraLarge = {
  getPrice: function(){return this.basePrice + 10},
  getLabel: function(){return this.name + ' extra large'}
};

coffeeTypes.push(Peruvian);
coffeeSizes.push(extraLarge);

Arrays of coffee objects and size objects are "mixed" together,—that is, their methods and member variables are combined—with a custom function called plusMixin (see Chapter 7, Functional and Object-oriented Programming in JavaScript). The coffee type classes contain the member variables and the sizes contain methods to calculate the name and price. The "mixing" happens within a map operation, which applies a pure function to each element in an array and returns a new function inside a reduce() operation—another higher-order function similar to the map function, except that all the elements in the array are combined into one. Finally, the new array of all possible combinations of types and sizes is iterated through with the forEach() method The forEach() method is yet another higher-order function that applies a callback function to each object in an array. In this example, we provide it as an anonymous function that instantiates the objects and calls the printPrice() function with the object's getPrice() and getLabel() methods as arguments.

Actually, we could make this example even more functional by removing the coffees variable and chaining the functions together—another little trick in functional programming.

coffeeTypes.reduce(function(previous, current) {
  var newCoffee = coffeeSizes.map(function(mixin) {
    // `plusMixin` function for functional mixins, see Ch.7
    var newCoffeeObj = plusMixin(current, mixin);
    return new newCoffeeObj();
  });
  return previous.concat(newCoffee);
},[]).forEach(function(coffee) {
  printPrice(coffee.getPrice(),coffee.getLabel());
});

Also, the control flow is not as top-to-bottom as the imperative code was. In functional programming, the map() function and other higher-order functions take the place of for and while loops and very little importance is placed on the order of execution. This makes it a little trickier for newcomers to the paradigm to read the code but, once you get the hang of it, it's not hard at all to follow and you'll see that it is much better.

This example barely touched on what functional programming can do in JavaScript. Throughout this book, you will see even more powerful examples of the functional approach.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.144.119.170