How you're a functional programmer and you may not even realize it 🕵️‍♂️
Tags: javascript, functional
Published: 2021-06-22 23:01:36

So you have that one hipster "functional programmer" coworker... They ramble on about their side projects in Elm, why JavaScript is too mainstream, how they've learned Haskell because *it's a different way of thinking about things*, and have tried explaining what *currying* and a *monad* is to you several times. With a slew of new terms and languages you haven't even heard of, it's easy to dismiss your coworker's *functional programming* ideas as fringe concepts.

You're a JavaScript developer that has heard about functional programming in passing, but haven't committed the time to dive into it fully. What if I told you are probably already a functional programmer in disguise? You're probably already using loads of functional programming concepts without even knowing it. Before we explore some ways in you're already writing functional code, let's define some basic functional programming concepts.



## Functional programming dumbed down without much extra terminology

Ignore *currying*, *monads*, and other terms that are often associated with functional programming. Functional programming at its core is to code with *pure functions*. There's two rules of pure functions:

1. The **same inputs** always return the **same output**. No matter how many times the function is called, what order it's called in, or what environment the function is running, it will always have a consistent output.
2. The function does not have an effect on anything outside the function. No modifying the parameters, changing a variable outside of the function scope, or making http calls. This is often called **no side effects**.



## Advantages of using pure functions over impure functions

* Pure functions are more testable and predictable, because the same inputs return the same outputs.
* Pure functions are usually more readable (*easier to reason about*), because you don't need to think about the effects of outside state on your function. Refactoring becomes easier; if you have a function that is confusing, you can write a unit test for the existing function and replace or rewrite it with the new implementation without worrying too much about breaking existing code.
* Pure functions are usually more reusable. Once you start writing pure functions, they'll typically be smaller because you can't rely on outside state. Small functions typically only *do one thing*, so they're inherently more reusable across your application.



## How you're already using pure functions

Chances are, you've written many pure functions before. Here are some clues that you're actually already a functional programmer.



## Using [].map instead of [].forEach or a for loop

Like forEach or a for loop, `map()` iterates over an array. The difference is, map will not change (or *mutate*) the original array. Map always returns a new array. Let's take an example function that capitalizes all items in a list and implement it with for, forEach, and map:

```js
const list = ['apple', 'banana', 'carrot'];
const capitalized = capitalizeList(list);
```

Using **for**
```js
function capitalizeList(list) {
  for (let i = 0; i < list.length; i++) {
    list[i] = list[i].toUpperCase(); 
  }

  return list;
}

```

Using **forEach**
```js
function capitalizeList(list) {
  let newList = [];
  list.forEach(item => {
    newList.push(item.toUpperCase());
  });
  return newList;
}
```

Using **map**
```js
function capitalizeList(list) {
  return list.map(item => item.toUpperCase());
}
```

You may have written the third option before or prefer it due to its conciseness. It's also the most pure. The **for loop** example modifies the original array, so it is impure. The capitalizeList **forEach** example will always return the same input and output, but the forEach function inside of capitalizeList is not pure because it relies on outside state. The **map** example is completely pure; both capitalizeList and the map function do not produce any side effects. Preferring **map** over the other options means you're probably writing many pure functions.



## Using filter, reduce, find, or a host of other array pure functions

Like `map()`, `filter()` and `reduce()` will also not change the original array.

Filter using **for**
```js
function filterByLetter(list, letter) {
  for (let i = 0; i < list.length; i++) {
    if (!list[i].startsWith(letter)) {
      list.splice(i, 1);
    }
  }
  return list;
}
```

**[].filter**
```js
function filterByLetter(list, letter) {
  return list.filter(item => item.startsWith(letter));
}
```

Finally, reduce can be used to take an array and turn it into a new data type.

Summing numbers using **for**
```js
function sumNumbers(numbers) {
  let sum = 0;
  for (let i = 0; i < numbers; i++) {
    sum += numbers[i];
  }
  return sum;
}
```

Summing numbers using **[].reduce**
```js
function sumNumbers(numbers) {
  return numbers.reduce((a, b) => a + b, 0);
}
```

Reduce is a little more advanced and merits its own article, but understanding it and using it should help with building more pure functions. Here are some more examples of pure functions in JavaScript that you may have used before:

| Pure Function | What's it for? |
| ----------- | -- |
| [].map() | Returning a new array of new items |
| [].filter() | Filtering arrays |
| [].reduce() | Morphing arrays into new data structures |
| [].find() | Finding first occurrence of item |
| [].some() | Checking if array has at least one item matching criteria |
| [].includes() | Checking if array has at least one item matching raw param value |
| [].every() | Checking if array has ALL items matching criteria |
| [].slice(start, end) | Trims array at positions  |
| [].concat() | Merging two arrays together  |
| [].join() | Converting array to a single string |
| [].flatMap() | Converting a 2D-array into a single array |

It's worth mentioning some common impure functions that modify the original array:

| Impure Function | What's it for? |
| ----------- | -- |
| [].push() | Adding to an array |
| [].pop() | Removing an item from array |
| [].sort() | Sorting |
| [].shift() | Removing first item in array |
| [].unshift() | Adding items to the beginning of the array |
| [].splice() | Removing/replacing items in array |
| [].reverse() | Reversing the order |




## Using const instead of var or let
JavaScript essentially phased out `var` and replaced it with `let` and `const` in 2016. If you've ditched var, you're already on the right track. `let` (and var) allows you to reassign variables:

```js
let vegetable = 'asparagus';
vegetable = 'broccoli'; // valid JavaScript

var carb = 'rice';
carb = 'bread'; // valid JavaScript
var carb = 'beans'; // also valid JavaScript
```

`const` will not allow you to reassign variables

```js
const legume = 'chickpea';
legume = 'soybean'; // syntax error
```

In the above capitalizeList example, notice how `let` is present in the impure examples. If you program only with `const`, you're forced to write more pure functions.

## Using Object spread {...} notation

It's worth mentioning that const isn't completely immutable - you can still modify objects: 

```js
const snacks = {
  healthyOption: '',
  unhealthyOption: 'Cookies'
}

const addHealthyOption = (snacks, healthyOption) => {
  snacks.healthyOption = healthyOption;
  return snacks;
}

const newSnackObject = addHealthyOption(snacks, 'Edamame');

console.log(newSnackObject) // 😊 { healthyOption: 'Edamame', unhealthyOption: 'Cookies' }
console.log(snacks.healthyOption) // 😦 'Edamame'
```

In this example, addHealthyOption mutated the original object. This can be avoided using the object spread syntax:

```js
const addHealthyOption = (snacks, healthyOption) => {
   return {...snacks, healthyOption}
}

const newSnackObject = addHealthyOption(snacks, 'Edamame');

console.log(newSnackObject) // 😊 { healthyOption: 'Edamame', unhealthyOption: 'Cookies' }
console.log(snacks.healthyOption) // 😊 ''
```



## Using array spread [...x]

Like the above example, array spreading is similar to object spreading. Let's refactor the above example to take in arrays and look at the two implementations.

```js
const snacks = {
  healthyOptions: [],
  unhealthyOptions: ['Cookies']
}

const addHealthyOptions = (snacks, healthyOptions) => {
  snacks.healthyOptions.push(healthyOptions);
  return snacks;
}

const newSnackObject = addHealthyOptions(snacks, ['Edamame', 'Hummus and Veggies']);

console.log(newSnackObject) // 😊 { healthyOptions: ['Edamame', 'Hummus and Veggies'], unhealthyOptions: ['Cookies'] }
console.log(snacks.healthyOptions) // 😦 ['Edamame', 'Hummus and Veggies']
```

Notice how snacks was mutated. Writing this in a pure way can be accomplished by using the array spread feature:

```js
const snacks = {
  healthyOptions: [],
  unhealthyOptions: ['Cookies']
}

const addHealthyOptions = (snacks, healthyOptions) => {
  return {
     ...snacks,
     healthyOptions: [...snacks.healthyOptions, healthyOptions]
  }
}

const newSnackObject = addHealthyOptions(snacks, ['Edamame', 'Hummus and Veggies']);

console.log(newSnackObject) // 😊 { healthyOptions: ['Edamame', 'Hummus and Veggies'], unhealthyOptions: ['Cookies'] }
console.log(snacks.healthyOptions) // 😊 []
```



## Summary

When we write **pure functions** (same input, same outputs and no side effects) we're *doing functional programming*. These features can help us write pure functions:

* Using .map() and other array methods like filter, find, and reduce that do not modify the original array
* Using const instead of let or var
* Using {...x} or [...x] to create new objects and arrays

If you've used any of these features, you've probably already written many pure functions. You can call yourself a functional programmer. Inevitably, it becomes harder and harder not to produce side effects or rely on outside state in your functions. This is where advanced functional programming concepts like **closures**, **higher order functions**, and **currying** come in. I did not focus on these advanced topics, because if you're new to functional programming, you're probably not already *currying functions* on a day-to-day basis. After you've mastered the basics, check out some of these resources to take you functional programming game to the next level:

* https://www.youtube.com/watch?v=qtsbZarFzm8: **Anjana Vakil — Functional Programming in JS: What? Why? How?** - Great talk on functional programming
* https://mostly-adequate.gitbook.io/mostly-adequate-guide/: **Professor Frisby's Mostly Adequate Guide to Functional Programming** - In-depth, free book that explains more advanced concepts.