Tuesday, January 24, 2017

Filtering and Chaining in Functional JavaScript

One of the things I appreciate about JavaScript is its versatility. JavaScript gives you the opportunity to use object oriented programming, imperative programming, and even functional programming. And you can go back and forth among them depending on your current needs and the preferences and expectations of your team.

Although JavaScript supports functional techniques, it's not optimized for pure functional programming the way a language such as Haskell or Scala is. While I don't usually structure my JavaScript programs to be 100 percent functional, I enjoy using functional programming concepts to help me keep my code clean and focus on designing code that can be reused easily and tested cleanly.

Filtering to Limit a Data Set

With the advent of ES5, JavaScript Arrays inherited a few methods that make functional programming even more convenient. JavaScript Arrays can now map, reduce, and filter natively. Each of these methods goes through every one of the items in an array, and without the need for a loop or local state changes, performs an analysis that can return a result that's ready to use immediately or pass-through to be operated on further.

In this article I want to introduce you to filtering. Filtering allows you to evaluate every item of an array, and based on a test condition you pass in, determine whether to return a new array that contains that element. When you use the filter method of Array, what you get back as another array that is either the same length as the original array or smaller, containing a subset of the items in the original that match the condition you set.

Using a Loop to Demonstrate Filtering

A simple example of the sort of problem that might benefit from filtering is limiting an array of strings to only the strings that have three characters. That's not a complicated problem to solve, and we can do it pretty handily using vanilla JavaScript for loops without the filter method. It might look something like this:

var animals = ["cat","dog","fish"];
var threeLetterAnimals = [];
for (let count = 0; count < animals.length; count++){
  if (animals[count].length === 3) {
    threeLetterAnimals.push(animals[count]);
  }
}
console.log(threeLetterAnimals); // ["cat", "dog"]

What we're doing here is defining an array containing three strings, and creating an empty array where we can store just the strings that only have three characters. We're defining a count variable to use in the for loop as we iterate through the array. Every time that we come across a string that has exactly three characters, we push it into our new empty array. And once were done, we just log the result.

There's nothing stopping us from modifying the original array in our loop, but by doing that we would permanently lose the original values. It's much cleaner to create a new array and leave the original untouched.

Using the Filter Method

There's nothing technically wrong with the way that we did that, but the availability of the filter method on Array allows us to make our code much cleaner and straightforward. Here's an example of how we might've done the exact same thing using the filter method:

var animals = ["cat","dog","fish"];
var threeLetterAnimals = animals.filter(function(animal) {
  return animal.length === 3;
});
console.log(threeLetterAnimals); // ["cat", "dog"]

As before, we started with a variable that contains our original array, and we defined a new variable for the array that's going to contain just the strings that have three characters. But in this case, when we defined our second array, we assigned it directly to the result of applying the filter method to the original animals array. We passed filter an anonymous in-line function that only returned true if the value it was operating on had a length of three.

The way the filter method works, it goes through every element in the array and applies the test function to that element. If the test function returns true for that element, the array returned by the filter method will include that element. Other elements will be skipped.

You can see how much cleaner the code looks. Without even understanding ahead of time what filter does, you could probably look at this code and figure out the intention.

One of the happy by-products of functional programming is the cleanliness that results from reducing the amount of local state being stored, and limiting modification of external variables from within functions. In this case, the count variable and the various states that our threeLetterAnimals array was taking while we looped through the original array were simply more state to keep track of. Using filter, we've managed to eliminate the for loop as well as the count variable. And we're not altering the value of our new array multiple times the way we were doing before. We're defining it once, and assigning it the value that comes from applying our filter condition to the original array.

Other Ways to Format a Filter

Our code can be even more concise if we take advantage of const declarations and anonymous inline arrow functions. These are EcmaScript 6 (ES6) features that are supported now in most browsers and JavaScript engines natively.

Continue reading %Filtering and Chaining in Functional JavaScript%


by M. David Green via SitePoint

No comments:

Post a Comment