This post was originally published on my blog
One of the hot topics right now in the web development world is functional programming in the language of the web, JavaScript.
Functional programming encompasses a whole host of mathematical properties and phenomena that is beyond this post, but what I am going to address here is how to write a a few functions with nominal functional programming.
This is going to be a series. I am currently researching these topics as I go along and what I find excites me. I will be digging into these topics, each array method bit by bit. You can find some more of this on Steve Smith’s blog Funky JavaScript.
Important Concept: Higher Order Functions
One of the best and worst parts about JavaScript is that you can pass functions into other functions. This can lead to beautifully expressive code and sometimes bugs.
Why can we do this? Because, like in most functional programming languages 1, functions are values just like any other value in JavaScript.
Take this code:
// Named function or
// function declaration
function double(x) {
return x * 2;
}
// Anonymous function or
// Function expression
let double = function(x) {
return x * 2;
}
let cat = double;
// Function call
cat(60);
Here we have named function called double
. It takes an argument, x
and when you call it, it returns whatever the value of x is that you specify in the function call and returns it.
What’s different about JavaScript is that you can pass it into a variable and call the function from that variable. This is because, well, functions are values.
Higher order functions are good for composition to take smaller functions and make them into bigger functions. More on this in a minute.
Enter .filter()
The .filter()
function is an array function that takes a callback that it uses to create a new filtered version of an array.
Take this array of objects:
const animals = [
{ name: ‘Catticus Finch’, species: ‘cat’ },
{ name: ‘Peaches’, species: ‘fish’ },
{ name: ‘Bobby’, species: ‘dog’ },
{ name: ‘Lucifer’, species: ‘cat’ },
{ name: ‘Beatrix’, species: ‘rabbit’ },
{ name: ‘Cerulean’, species: ‘fish’ }
];
Say I wanted to filter out all the cats in this array. We could use the trusty for
loop:
const cats = [];
for (let i = 0; i < animals.length; i++) {
if (animals[i].species === ‘cat’) {
cats.push(animals[i]);
}
}
We are essentially just looping through the array and for every cat the for
loop finds, it pushes it into the empty cat
array.
Now, we can filter.
Filter accepts a callback and loops through each item in the array and passes it back to the callback function. .filter()
expects a boolean and then returns the filtered array.
const cats = animals.filter(function(animal) {
return animal.species === ‘cats’;
});
Here, if the value of the species
property in the animals
array is a cat
it will return the names of those cats in a filtered array.
We could also write an anonymous function and add a filter function inside of it, much like this:
const isCat = function(animal){
return animal.species === ‘cats’;
});
const cats = animals.filter(isCat);
How Cool is This?
Writing small functions allows composition which we can reuse. In the for loop, we are pushing cats into the array but filter handles this natively.
Filter and the callback are composed as they are meshed into each other. Not only is it syntactically pleasing, but it is less lines of code which is always a good thing.
Next Up
Next I want to tackle the .map()
function and get back to my Chrome DevTools series.
-
Though JavaScript isn’t a purely functional programming language. ↩
Top comments (41)
I like this article, it's very clear. Well done! The only comment I have are about the semantics around
filter
. To "filter" means to "remove", so I would think (or presume) that a filter is an exclusive filter and not an inclusive filter like you use it.I know this all comes down to semantics, so I'm sure it's a matter of opinion, but when I read
filter(isCat)
I feel that it shouldn't contain cats.What is your opinion about this?
Some dictionaries use "remove" in their definition but most define the verb filter as simply passing something through a filter (noun). As a verb, filter is most often followed by either "for" or "out" to make it clear. So even in the 1800's I think a gold miner would say he is using his mesh pan "to filter for gold".
I accept your explanation, and I fully understand it, albeit I don't agree. When working with computers, a filter means to take impurities out, e.g. a spam filter. So I do understand that this is due to dynamics of a language, but if it was in my code I'd be confused if I saw it used this way.
But again, thanks for your comment :).
I think that the meaning of "filter" remains the same. And the concept we can apply in programming is filter removes the "impurities", keeping only the desirable data by passing the a parameter (the desirable condition).
This bothers me too.
The callback must return true to include the element in the resultant array, and if we were using filter to remove cats, then we'd need isCat to return false if the element was a cat or to rename it to isNotCat and make it keep returning true. That means either way we can't use that function in both filter and our own code without going insane.
Oh, and in response to your next comment (which for some reason dev.to doesn't let me reply to directly): we have an existing convention of referring to filters on search forms but what they include. If you go to Amazon and search for something, the filters aren't all like "do not include fish food in my results" because that would also be unsuitable for happy life.
I hear you, Joseph. I always had to stop and think about filter until I started thinking of it as a "WHERE" clause in SQL.
When I see
filter(isCat)
I immediately think of it asWHERE isCat
.This is well laid out Tiffany. The idea of passing functions around is often a new perspective for folks when first learning Javascript.
Thanks for sharing with us :)
Great writeup, Tiffany. Super clear.
Thanks Ben!
I find myself writing more and more functional code in Javascript. To me, it's more elegant, readable and easier to test. I'm still learning how to do it properly but, as you mentioned, Javascript not being a purely functional programming, it takes some discipline and patience to stick to it.
I am really loving how elegant it is. I am still working through learning it, but gosh. Such a better way to go about it. Trying to force JavaScript into OOP may be to its detriment. Still, it is ubiquitous and whatever ECMA decides to do, whichever direction they want to go, I am onboard. Exciting times.
wat u talkin bout willis? js is oop. literally everything is javascript is an object. even a strings an numbers are natural objects in js. you can do "mystring".length because a string is an object with a length property. you can do (123.123).toFixed() because all numbers are objects with a toFixed method. if you think you have to "force" js into oop then you don't understand the language.
What I actually meant by that is using Classical Inheritance with faux classes and instantiating a new object with things like the
new
keyword instead of Prototypal Inheritance. Prototypal inheritance is more flexible and is probably the best part of JavaScript's OOP implementation.Good to hear you say that. I fully agree. Most people don't like the whole prototype thing but I love it.
Coming from doing Java at university, it's taken a while to dig prototypes. I am still working on learning to actually love it. But I understand its power.
why in heaven can't you use regular quotes (') so one can copypaste the code and play around? and why don't you use arrows to make code short, like it's 2017?
let cats = animals.filter(a=>a.species==='cats');
None of what you have said here really matters. I'm making a point, syntax aside. If you want to play around with some code, I suggest you find the code that is syntactically more pleasing to you, as I won't change this. I also don't really need to explain myself.
Is this really a constructive comment? The author's code is readable and correct. Using arrow functions doesn't change the point of the article.
sort of does actually, if we're talking about functional programming you should ideally be using arrow functions as they don't bind
this
, therefore they're better suited for functional programmng.I am not sure that using this in functional programming is recommended. If you don't need to bind this, it means that you need to access the outer this scope right? Therefore, this function is not pure anymore and doesn't solely rely on its arguments. Or am I not understanding something ?
There is also the problem of readability with arrow functions. The syntax is shorter, no doubt, but functions are anonymous. It might not always be useful to trade readability for shorter code.
Exactly. Anything that binds "this" is oop, not functional. Arrow functions do not, so they're better suited for truly functional programming.
Something that I think it would be nice to mention, is that the first change you see while you're writing functional programming, is that you're writing less code. But this is just an small consequence of other bigger concept.
The main difference between the for loop and the filter, is that you as a programmer don't have to be aware of how to do the filtering inside the list. You're focus on "what to do" (filter) and not "how to do it" (for loop). This cool concept is there every time you're writing functional programming, because it allows you to be more Declarative and less imperative :D
Hey, first of all thank you for your article. What I have to say might sound a little offensive but I have to say it. Things like the filter method that you mentioned have been present in the programming world for ages. Think of extension methods. LINQ. What I don't understand is how people connect functional programming like it is something so new and powerful, but it is been there for long time and people use it every day. LINQ has a lot of extension methods far more powerful than filter. The thing is that using methods like filter is not even functional programming in my opinion. It is just an extension method on an Array object (C# terminology). Map will also be the same. Functional programming is far more than map and filter. But it is not the silver bullet. It will not solve your problems especially if you are working on complex domain logic. Just think about it. People had the functional style lying around, but history has proven that it is far more better to solve complex domain with Domain Driven Design rather than functional style, that is why they used DDD.
I feel like this hype around FP is cluttering people minds. People start to see OOP like it is a bad thing. Writing pure functions is good, but it will not solve all of your problems. Your code will never be close to the domain logic. It might be closer to the developers. And that is not what you want on big projects.
Read about DDD and OOP and think of how you will solve complex domains using DDD and how will you solve them using FP.
Yes yes and yes! The amount of silly assertions around the FP stuff is just incredible. Loops are bad, classes are bad, conditionals are bad ... even if it makes more sense to write something in an imperative way, the FP approach is by definition better even if it's clumsier and more difficult to read. I'm tired of always seeing the trivial filter, map and reduce stuff, like all of the problems in the real world can be solved with these functions (which are useful of course, but not for everything!!!!!).
I understand that FP has been around for a long time and that it is more than
filter
andmap
. But all of the intricacies of FP are far beyond the scope of this post.I don't think OOP is bad at all. I don't think one way is better than another. OOP is still relevant when it comes to large scale systems. I was just excited to learn about these methods. Good points you've made here, though.
If you want to talk about things that have been around for years, you really should go much further back. Lisp (functional) has been around for a very long time. OOP has been around a long time too, starting as lisp atoms. FP isn't new, but it's gaining popularity.
We're already at the age where everything old is new again with computers, but each iteration brings improvements. The tools to program with OOP and FP have come a long way, and the abstractions we're capable of now are definitely better.
There is a lot more to functional programming than what's in this post, of course, but the essence of passing functions as values is one of its pillars. Another pillar that wasn't covered (you can't cover everything in one post) is that you need your functions to behave in a predictable manner, such that repeated calls with the same parameter will return the same value, no matter how many times you call it, or in what order.
Very nice! The whole idea of functional programming in is is very appealing because it really brings some structure to the language. JavaScript has been like the wild west for such a long time, where inheriting a codebase meant rewriting it half of the time because it was so difficult to find what's going on. I feel like functional programming and frameworks really give us a nice way to standardise what we're writing.
Looking forward to the next post!
//this code doesn't work
let cats = animals.filter(function(animal) {
return animal.species === ‘cats’;
});
// this does
let cats = animals.filter(function(animal) {
return animal.species === 'cat';
});
Yeah I see that. Thanks.