> For the complete documentation index, see [llms.txt](https://mihai-gheorghe.gitbook.io/tic/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://mihai-gheorghe.gitbook.io/tic/advanced-javascript/functional-programming.md).

# Functional Programming

## Principles

* Separate data from behavior
* Use of declarative functions (as opposed to imperative, see [Programming paradigms](/tic/advanced-javascript/programming-paradigms.md#imperative-and-declarative-code))
* Pure functions
* Immutable data
* Proper use of caching (computing efficiency)
* Composing (chained atomic pure operations)

In JavaScript, functions are values: they can be stored in variables, passed as arguments and returned by other functions. A function that takes or returns another function is a **higher-order function**. The array methods `map()`, `filter()` and `reduce()` (see [ES6 and later](/tic/advanced-javascript/es6.md#array-methods-for-functional-code)) are higher-order functions and the everyday tools of this style: they return new values instead of changing the original array.

## Pure functions

* Don't cause side effects: they don't change the global state or their arguments
* Always have a return statement. This is useful for chaining purposes
* Deterministic: on the same input, they always return the same output

```javascript
//Side effects:
const array = [1,2,3];
function mutateArray(arr) {
  arr.pop()
}
function mutateArray2(arr) {
  arr.forEach(item => arr.push(1
  ))
}
//The order of the function calls will matter.
mutateArray(array)
mutateArray2(array)
array // [1, 2, 1, 1]; in the opposite order it would be [1, 2, 3, 1, 1]
```

```javascript
// Deterministic or not:
function notGood() {
  return Math.random()
  // new Date();
}

function good() { //pure function
  return 5
}

Math.abs(Math.abs(-10)) // pure, and also idempotent: applying it twice gives the same result as once
```

## Immutability

Instead of changing existing data, functional code creates new values. The spread operator (see [ES6 and later](/tic/advanced-javascript/es6.md#spread-operator)) makes copies easy:

```javascript
const cart = ['apple', 'pear'];
const newCart = [...cart, 'plum'];       // cart is unchanged

const user = { name: 'Ana', age: 20 };
const olderUser = { ...user, age: 21 };  // user is unchanged
```

When functions never change shared data, the order in which they are called no longer matters, as it did in the side-effects example above.

## Memoization

**Memoization** stores the result of a function for each argument, so that a repeated call returns the stored result instead of computing it again. It only works for pure functions, whose result depends only on their arguments.

```javascript
//Memoization
//learn to cache
function addTo80(n) {
  return n + 80;
}

addTo80(5)

let cache = {};
function memoizeAddTo80(n) {
  if (n in cache) {
    console.log('quickly retrieved from cache');
    return cache[n];
  } else {
    console.log('expensive operation');
    const answer = n + 80;
    cache[n] = answer;
    return answer;
  }
}
```

Here is a better implementation, with no global state: the cache lives in a [closure](/tic/advanced-javascript/runtime-engine-callstack.md#closures).

```javascript
// let's make that better with no global scope.
function memoizeAddTo80() {
  let cache = {};
  return function(n) { //This is closure in javascript.
    if (n in cache) {
      console.log('quickly retrieved from cache');
      return cache[n];
    } else {
      console.log('expensive operation');
      const answer = n + 80;
      cache[n] = answer;
      return answer;
    }
  }
}

const memoized = memoizeAddTo80();
console.log(1, memoized(6))
// console.log(cache)
// console.log('-----------')
console.log(2, memoized(6))
```

## Currying and Composing

**Currying** in JavaScript transforms a function that takes multiple arguments into a sequence of functions, each taking a single argument. For example, a function `f(a, b)` becomes `f(a)(b)`. It allows partial application of functions, where you can fix some arguments and pass others later, enabling more flexible function usage.

```javascript
// add two numbers
const add = a => b => a + b;

//similar to
const add2 = a => {
    return b => {
        return (a + b)
        }
    }

const result = add(2)(3); // => 5
```

### pipe() and compose()

Composing is the process of chaining functions. In other words, through `pipe()` and `compose()` we create a pipeline of functions with the output of one function connected to the input of the next. This is the reason for which these functions need to be pure.

{% tabs %}
{% tab title="chaining functions" %}

```javascript
//as seen on freecodecamp.org/news/pipe-and-compose-in-javascript-5b04004ac937/

//Let’s write a function that returns someone’s name.
const getName = (person) => person.name;
getName({ name: 'Buckethead' });
// 'Buckethead'

//Let’s write a function that uppercases strings.
const uppercase = (string) => string.toUpperCase();
uppercase('Buckethead');
// 'BUCKETHEAD'

//What if we want to add a function that gets the first 6 characters of a string?
const get6Characters = (string) => string.substring(0, 6);
get6Characters('Buckethead');
// 'Bucket'

//Let’s get really crazy and add a function to reverse strings.
const reverse = (string) =>
  string
    .split('')
    .reverse()
    .join('');

reverse('Buckethead');
// 'daehtekcuB'


//chaining all the operations would result in
reverse(get6Characters(uppercase(getName({ name: 'Buckethead' }))));
// 'TEKCUB'
```

{% endtab %}
{% endtabs %}

Instead of jamming functions within functions or creating a bunch of intermediate variables, let’s `pipe` all the things!

```javascript
// Function composition enabling pipe functionality using reduce()
const pipe = (...functions) => input => functions.reduce(
    (acc, fn) => fn(acc),
    input
)
```

{% tabs %}
{% tab title="pipe" %}

```javascript
pipe(
  getName,
  uppercase,
  get6Characters,
  reverse
)({ name: 'Buckethead' });
// 'TEKCUB'
```

{% endtab %}
{% endtabs %}

`compose()` is similar, it just deals with the chain in the opposite direction (from right to left).

```javascript
const g = n => n + 1;
const f = n => n * 2;

const h = x => f(g(x))
h(30); //=> 62

const compose = (f, g) => x => f(g(x));
compose(f,g)(30); //=> 62
```

## OOP vs. functional programming

|                       | OOP                                                                                      | Functional programming                                                 |
| --------------------- | ---------------------------------------------------------------------------------------- | ---------------------------------------------------------------------- |
| Organizes code around | objects that hold data and the methods that change it                                    | functions that receive data and return new data                        |
| State                 | kept inside objects and changed over time (stateful)                                     | avoided: new values instead of changes (stateless)                     |
| Side effects          | common: methods change the object                                                        | avoided: pure functions                                                |
| Style                 | mostly imperative: how to do it                                                          | mostly declarative: what to obtain                                     |
| Fits well             | many kinds of entities with their own behavior, such as UI components or game characters | data transformations, such as filtering, mapping and aggregating lists |

## Takeaways

* Functions are values: higher-order functions such as `map()`, `filter()` and `reduce()` take other functions as arguments.
* Pure functions and immutable data make code predictable: the same input always gives the same output, and nothing else changes.
* Small pure functions can be cached (memoization), curried and composed into pipelines.
