Functional JavaScript Cheatsheet

If it has functions, it's a functional langugage

#Basics

Intro to Functional JavaScript

Functional programming has several principles:
- No side effects (e.g. changing of memory states by variable). Some claim, this only applies to global variables. Yet, mutating any data at all is to be avoided in functional programming.
- Working with Higher Order Functions and Pure Functions.
They are a side effect of the idea to make everything revolve around expressions, instead of statements.

Pure Functions

// for each x, y will be returned (f(x)=x^2)
function square(x) {
  return x*x
}
square(2) // 4
square(3) // 9
Like functions in mathematics, Pure Functions return exactly what you expect. They can also get parameters, but usually do not access unpredictable things like Date.now().
For every same input it returns the same output (deterministic).

Higher-Order Functions

function higherOrder(secondFunction) {
  return secondFunction
}

function f() {
  return "f-function"
}

higherOrder(f)      // [Function: f]
higherOrder(f)()    // f-function
A higher-order-function is a function, that receives a functions as a parameter, and returns one.

Currying Functions

const greet = (time, title, lastname) => {
  console.log(
      `Good ${time}, ${title} ${lastname}`
  )
}
greet("Morning", "Mr.", "Mozart")
// Good Morning, Mr. Mozart
const greet = time => 
  title => 
      lastname => 
          `Good ${time}, ${title} ${lastname}`

greet("Morning")("Mr.")("Mozart")
Below you see the same function just curried. By currying the function is partially applied, where the function arguments are passed one after the other and in the meantime are held in a new function, which can be reused arbitrarily.

Haskell-like, curried function

add = (a) => (b) => a + b
// no "let" or "const needed
add(2)(3) // 5
// is the same as: 
function add(a) {
  return function(b) {
    return a + b
  }
}
Below you see the same function just curried. By currying the function is partially applied, where the function arguments are passed one after the other and in the meantime are held in a new function, which can be reused arbitrarily.

#Map

Map

const data = [
    {name: "Max", age: 24},
    {name: "Tom", age: 21},
    {name: "Anna", age: 24},
    {name: "Carl", age: 29}
  ]
  
  const names = data.map((obj) => {
    return obj.name
  })
  
  names // [ 'Max', 'Tom', 'Anna', 'Carl' ]
Map is a high-order function. It passes through every element in the array, and returns the name of every element. This name is then stored in an array. It transforms an array of objects into an array.

Mapping twice

// using data from the previous Map example
const names = data.map((obj) => obj.name).map(
  name => "Person: " + name
)

names /* [ 'Person: Max', 
'Person: Tom', 'Person: Anna', 
'Person: Carl' ] */
Map can be chained. Using the same basis like in the example before, we now can map again, to add something to each element of our resulting array.

Map for updating & shorthand

let arr = [1, 2, 3, 4]

// update the array with doubled values
arr = arr.map(item => {
  return item * 2 
})
// alternative, shorthand syntax
arr = arr.map(item => item * 2)
Yes, with map we can map over object and update it the same time.

#Filter & Reduce

Reduce

let nums = [1, 2, 3]

nums.reduce((prev, current) => {
	return prev + current
})
// 6
Reduce reduces an array, based on a calcuting, onto a single value. In this case, everything is added up, so 6 is the result of 1 + 2 + 3.

Filter

let nums = [1, 2, 3, 4]

nums.filter((num) => {
	return num % 2 === 0
})
// [2, 4]

Filter filters an array based on a pattern. The pattern-function returns true for the value which should be in the resulting, filtered array.

Filter / Reduce - external function

let nums = [1, 2, 3, 4]

function evenFilter(num) {
	return num % 2 === 0
}

nums.filter(evenFilter)
Instead of writing an anonymous function and passing it into Map / Reduce / Filter, we can use a global one.

#Immutability

Understanding immutability

Immutability is a central concept of functional programming. An object is immutable, if its state can not be changed. A common misconception is that the const keyword would make a variable immutable. This is not the case, as we are going to see. Not understanding this concept can lead to bugs in code. While JavaScript offers for example Object.freeze() as a solution, there are libraries out there. To name a few: Immutable.js or Ramda. Also, PureScriptcan help to write functional code for the web.

const for immutability?

const number = 42
number = 24
// Error! Number is immutable.
const person = {
  name: 'Max',
}

person.name = 'Carl'
// will work
While primitive data types are immutable through const, object aren't.

Unintentional object mutation

const person = {
	name: 'Max',
}

let person2 = person
person2.name = 'Carl'

console.log(person.name) // Carl
Object can even be mutated through mutating their copies.

Object.freeze even changes copying

const person = {
	name: 'Max',
}
Object.freeze(person)

let person2 = person
person2.name = 'Carl'

console.log(person.name) // Max

Object.freeze for immutability

const person = {
	name: 'Max',
}
Object.freeze(person)

person.name = 'Carl'
No error, but person.name is still Max.