Functional vs Imperative Patterns in JavaScript
Tags: functional, javascript, mojiscript
Published: 2018-10-16 18:25:24

---
title: Functional vs Imperative Patterns in JavaScript
published: true
description: 
tags: functional, javascript, mojiscript
---

The intention of this post is not to say one paradigm is better than the other. It is just to show common patterns you run into and their functional equivalents.

If there is a pattern I missed and you would like to see, post it in the comments below. Warning, boil your pattern down to the least common denominators. I can't convert a 100 line function! ;)

# if / else

**Imperative**

```javascript
const hour = 14
let greeting

if (hour < 18) {
  greeting = 'Good day';
} else {
  greeting = 'Good evening';
}
```

**Functional**

The `if` can now be re-usable as function `getGreeting`.

A:

```javascript
const isDay = hour => hour < 18
const getGreeting = hour => isDay(hour) ? 'Good Day' : 'Good Evening'
const greeting = getGreeting (hour)
```

B:

```javascript
import ifElse from 'mojiscript/logic/ifElse'

const isDay = hour => hour < 18
const getGreeting = ifElse (isDay) (() => 'Good Day') (() => 'Good evening')
const greeting = getGreeting (hour)
```

# if (no else)

**Imperative**

```javascript
let name = 'joel'

if (name != null) {
  name = name.toUpperCase()
}
```

**Functional**

`isNotnull` and `toUpperCase` are re-usable functions. `name` is not overwritten, instead `upperName` is created.

```javascript
import when from 'mojiscript/logic/when'

const isNotNull = obj => obj != null
const toUpperCase = when (isNotNull) (string => string.toUpperCase ())

const name = 'joel'
const upperName = toUpperCase (name)
```

# Summing an Array

**Imperative**

```javascript
const values = [1, 2, 3]

let sum = 0
for (const x of values) {
  sum = sum + x
}
```

**Functional**

Do not mutate `sum`.

A:

```javascript
const values = [1, 2, 3]

const add = (x, y) => x + y
const sum = values.reduce(add)
```

B:

```javascript
import reduce from 'mojiscript/list/reduce'

const add = x => y => x + y
const sum = reduce (add) (0)

const values = [1, 2, 3]
sum (values)
```

# for / if (1)

**Imperative**

```javascript
const values = [1, 2, 3, 4, 5]

let evens = []
for (const x of values) {
  if (x % 2 === 0) {
    evens.push(x)
  }
}
```

**Functional**

Do not mutate `evens`.

```javascript
import filter from 'mojiscript/list/filter'

const values = [1, 2, 3, 4, 5]

const isEven = num => num % 2 === 0
const evens = filter (isEven) (values)
```

# for / if (2)

**Imperative**

```javascript
const values = [1, 2, 3, 4, 5]

for (const x of values) {
  if (x % 2 === 0) {
    console.log(`${x} isEven`)
  }
}
```

**Functional**

Use `when` for conditional execution.

```javascript
import map from 'mojiscript/list/map'
import when from 'mojiscript/logic/when'

const isEven = num => num % 2 === 0
const logWhenEven = when (isEven) (x => console.log (`${x} isEven`))

const values = [1, 2, 3, 4, 5]
map (logWhenEven) (values)
```

# Breaking a loop early

**Imperative**

```javascript
const values = [1, 2, 3]
let sum = 0
for (const x of values) {
  if (x > 3) break
  sum = sum + x 
}
```

**Functional**

`reduceWhile` is like `reduce`, but accepts a predicate to "break" early.

```javascript
import reduceWhile from 'mojiscript/list/reduceWhile'

const add = x => y => x + y
const lte3 = num => num <= 3

const sum = reduceWhile (() => lte3) (add) (0) (values)
```

# if / else if / else

**Imperative**

```javascript
const fn = temp => {
   if (temp === 0) return 'water freezes at 0°C'
   else if (temp === 100) return 'water boils at 100°C'
   else return `nothing special happens at ${temp}°C`
}

fn(0) //=> 'water freezes at 0°C'
fn(50) //=> 'nothing special happens at 50°C'
fn(100) //=> 'water boils at 100°C'
```

**Functional**

```javascript
import cond from 'mojiscript/logic/cond'
import $ from 'mojiscript/string/template'

const fn = cond([
  [0, 'water freezes at 0°C'],
  [100, 'water boils at 100°C'],
  [() => true, $`nothing special happens at ${0}°C`]
])

fn(0) //=> 'water freezes at 0°C'
fn(50) //=> 'nothing special happens at 50°C'
fn(100) //=> 'water boils at 100°C'
```

# Setting properties

**Imperative**

```javascript
const obj = {
  one: 1
}

obj.two = 2
```

**Functional**

Do not mutate original object, shallow clone it and then add the new prop.

note: When objects are mutable, you must deep clone. If objects are immutable, you can shallow clone, which has obvious performance benefits.

```javascript
const obj = {
  one: 1
}

const newObj = {
  ...obj,
  two: 2
}
```

# Modifying Arrays

**Imperative**

```javascript
const values = [1, 2, 3]
values.push(4)
```

**Functional**

Do not mutate `values`.

A:

```javascript
const values = [1, 2, 3]
const newValues = [...values, 4]
```

B: 

For large arrays, use an immutable library like [list](https://github.com/funkia/list) for high performance immutable Arrays.

```javascript
import L from 'list'

const values = L.from([1, 2, 3])
const newValues = L.append(4, values)
```

# Classes

**Imperative**

Prone to errors.

```javascript
class Cat {
  constructor() {
    this.sound = 'Meow'
  }

  talk() {
    return this.sound
  }
}

const cat = new Cat()
const talk = cat.talk

cat.talk() //=> 'Meow'
talk() //=> Error: Cannot read property 'sound' of undefined
```

**Functional**

Separation of function from data for maximum reusability.

```javascript
const cat = {
  sound: 'Meow'
}

const dog = {
  sound: 'Woof'
}

const talk = animal => animal.sound

talk (cat) //=> 'Meow'
talk (dog) //=> 'Woof'
```

# Nested for loop

**Imperative**

```javascript
let box = ''
for (let y = 0; y < 5; y++) {
  for (let x = 0; x < 5; x++) {
    box = box + '* '
  }
  box = box + '\n'
}
```

**Functional**

No more nesting. Immutable.

```javascript
import reduce from 'mojiscript/list/reduce'
import range from 'mojiscript/list/range'

const makeCols = cols =>
  reduce (acc => () => acc + '* ') ('') (range (0) (cols))

const makeBox = ({ cols, rows }) =>
  reduce (acc => () => `${acc}${makeCols (cols)}\n`) ('') (range (0) (rows))

const box = makeBox ({ cols: 5, rows: 5 })
//=> ​​​​​* * * * * ​​​​​
//=> ​​​​​* * * * * ​​​​​
//=> ​​​​​* * * * * ​​​​​
//=> ​​​​​* * * * * ​​​​​
//=> ​​​​​* * * * * ​​​​​
```

And reusable!

```javascript
const makeTriangle = length =>
  reduce
    (acc => i => `${acc}${' '.repeat(length - i)}${makeCols (i + 1)}\n`)
    ('')
    (range (0) (length))

const triangle = makeTriangle (5)
//=>​​​​​     * ​​​​​
//=>​​​​​    * * ​​​​​
//=>​​​​​   * * * ​​​​​
//=>​​​​​  * * * * ​​​​​
//=>​​​​​ * * * * * ​​​​​
```

# Null guard

**Imperative**

```javascript
const toUpper = string => {
  if (string != null) {
    return string.toUpperCase()
  }
}
```

**Functional**

A:

This example wraps the argument in a `Maybe` type and then unwraps it at the end. In a typical FP app, you would be using the `Maybe` throughout your app, so you would not need to wrap and unwrap the `string`. So this is a little more verbose than you would normally see.

```javascript
import S from 'sanctuary'

const toUpper = S.pipe ([
  S.toMaybe,
  S.map (string => string.toUpperCase ()),
  S.maybeToNullable
])

// If you use `Maybe` throughout your app, this would be your `toUpper` function.
const toUpper = S.map (string => string.toUpperCase ())
```

B:

`maybe` is a function decorator that executes the function only if an argument is supplied. Now our null guard is reusable. More on function decorators here: [Functional JavaScript: Function Decorators Part 2 #JavaScript](https://dev.to/joelnet/function-decorators-part-2-javascript-4km9)

```javascript
const maybe = func => (...args) =>
  args.length === 0 || args[0] == null
    ? args[0]
    : func(...args)

const toUpper = maybe(string => string.toUpperCase ())
```

# End

My articles are very Functional JavaScript heavy, if you need more FP, follow me here, or on Twitter [@joelnet](https://twitter.com/joelnet)!

**More articles**
[Ask me dumb questions about functional programming](https://dev.to/joelnet/ask-me-dumb-questions-about-functional-programming-bho)
[Let's make a DEV.to CLI... together](https://dev.to/joelnet/lets-make-a-devto-cli-together-4eh1)
[Let's talk about auto-generated documentation tools for JavaScript](https://dev.to/joelnet/lets-talk-about-auto-generated-documentation-tools-for-javascript-49ol)

![Cheers!](https://thepracticaldev.s3.amazonaws.com/i/6jsy3a866frzp3u5oda0.jpg)