The Powers of JavaScript's Functional Side - a Demonstration - Functional Programming in JavaScript (2015)

Functional Programming in JavaScript (2015)

Chapter 1. The Powers of JavaScript's Functional Side - a Demonstration

Introduction

For decades, functional programming has been the darling of computer science aficionados, prized for its mathematical purity and puzzling nature that kept it hidden in dusty computer labs occupied by data scientists and PhD hopefuls. But now, it is going through a resurgence, thanks to modern languages such as Python, Julia, Ruby, Clojure and—last but not least—JavaScipt.

JavaScript, you say? The web's scripting language? Yes!

JavaScript has proven to be an important technology that isn't going away for quite a while. This is largely due to the fact that it is capable of being reborn and extended with new frameworks and libraries, such as backbone.js, jQuery, Dojo, underscore.js, and many more. This is directly related to JavaScript's true identity as a functional programming language. An understanding of functional programming with JavaScript will be welcome and useful for a long time for programmers of any skill level.

Why so? Functional programming is very powerful, robust, and elegant. It is useful and efficient on large data structures. It can be very advantageous to use JavaScript—a client-side scripting language, as a functional means to manipulate the DOM, sort API responses or perform other tasks on increasingly complex websites.

In this book, you will learn everything you need to know about functional programming with JavaScript: how to empower your JavaScript web applications with functional programming, how to unlock JavaScript's hidden powers, and how to write better code that is both more powerful and—because it is smaller—easier to maintain, faster to download, and takes less overhead. You will also learn the core concepts of functional programming, how to apply them to JavaScript, how to side-step the caveats and issues that may arise when using JavaScript as a functional language, and how to mix functional programming with object-oriented programming in JavaScript.

But before we begin, let's perform an experiment.

The demonstration

Perhaps a quick demonstration will be the best way to introduce functional programming with JavaScript. We will perform the same task using JavaScript—once using traditional, native methods, and once with functional programming. Then, we will compare the two methods.

The application – an e-commerce website

In pursuit of a real-world application, let's say we need an e-commerce web application for a mail-order coffee bean company. They sell several types of coffee and in different quantities, both of which affect the price.

Imperative methods

First, let's go with the procedural route. To keep this demonstration down to earth, we'll have to create objects that hold the data. This allows the ability to fetch the values from a database if we need to. But for now, we'll assume they're statically defined:

// create some objects to store the data.

var columbian = {

name: 'columbian',

basePrice: 5

};

var frenchRoast = {

name: 'french roast',

basePrice: 8

};

var decaf = {

name: 'decaf',

basePrice: 6

};

// we'll use a helper function to calculate the cost

// according to the size and print it to an HTML list

function printPrice(coffee, size) {

if (size == 'small') {

var price = coffee.basePrice + 2;

}

else if (size == 'medium') {

var price = coffee.basePrice + 4;

}

else {

var price = coffee.basePrice + 6;

}

// create the new html list item

var node = document.createElement("li");

var label = coffee.name + ' ' + size;

var textnode = document.createTextNode(label+' price: $'+price);

node.appendChild(textnode);

document.getElementById('products').appendChild(node);

}

// now all we need to do is call the printPrice function

// for every single combination of coffee type and size

printPrice(columbian, 'small');

printPrice(columbian, 'medium');

printPrice(columbian, 'large');

printPrice(frenchRoast, 'small');

printPrice(frenchRoast, 'medium');

printPrice(frenchRoast, 'large');

printPrice(decaf, 'small');

printPrice(decaf, 'medium');

printPrice(decaf, 'large');

Tip

Downloading the example code

You can download example code files for all Packt books you have purchased from your account at http://www.packtpub.com. If you purchased this book elsewhere, you can visit http://www.packtpub.com/support and register to have the files e-mailed directly to you.

As you can see, this code is very basic. What if there were many more coffee styles than just the three we have here? What if there were 20? 50? What if, in addition to size, there were organic and non-organic options. That could increase the lines of code extremely quickly!

Using this method, we are telling the machine what to print for each coffee type and for each size. This is fundamentally what is wrong with imperative code.

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.

Summary

First, the benefits of adopting a functional style are clear.

Second, don't be scared of functional programming. Yes, it is often thought of as pure logic in the form of computer language, but we don't need to understand Lambda calculus to be able to apply it to everyday tasks. The fact is, by allowing our programs to be broken down into smaller pieces, they're easier to understand, simpler to maintain, and more reliable. map() and reduce() function's are lesser-known built-in functions in JavaScript, but we'll look at them.

JavaScript is a scripting language, interactive and approachable. No compiling is necessary. We don't even need to download any development software, your favorite browser works as the interpreter and as the development environment.

Interested? Alright, let's get started!