An introduction to MojiScript's enhanced map
Tags: javascript, mojiscript, showdev, functional
Published: 2018-10-30 16:44:45

---
title: An introduction to MojiScript's enhanced map
published: true
description: 
tags: javascript, mojiscript, showdev, functional
---

![World map](https://thepracticaldev.s3.amazonaws.com/i/h38jlrfkzqo771qvee7y.jpg)

MojiScript extends and enhances `map` in many ways like supporting iterables and asynchronous code. This an introduction into the features MojiScript's `map` provides and the differences with traditional `map`.

This post was inspired by an excellent question Twitter:

{% twitter 1052576566750916608 %} {% twitter 1052577088543297536 %}

# Traditional map

Let's start out with something you should already be familiar with. This is `map` in it's most simple form.

```javascript
const values = [1, 2, 3]
values.map(x => x * 2) //=> [2, 4, 6]
```

Now before we even begin this journey, I would like to recommend breaking the function `x => x * 2` out of the `map()` call. 

```javascript
const double = x => x * 2
const values = [1, 2, 3]
values.map(double) //=> [2, 4, 6]
```

I know it seems like I am saying something trivial and obvious, but it's something I rarely see when reading code.

This is something you can do with `map`, `filter`, `reduce`, `Promise.then` calls, and more.

# Syntax

MojiScript's `map` is a standalone function and not a method on an object. You still have the same `values`, `map`, and `func`. But the way you call it is just a little bit different (but not too much).

```javascript
// JavaScript
values.map(func)

// MojiScript
map (func) (values)
```

Making this change opens up the possibility to easily compose new functions.

```javascript
const newFunc = map (func) // a new function is born!
newFunc (values)
```

# Mapping Iterators

Because JavaScript's map is a method attached to `Array`, it cannot easily be used with other types.

In this example, I am importing `range`, which is an `Iterator`.

```javascript
import range from 'mojiscript/list/range'
console.log(...range (1) (4)) //=> 1 2 3
```

Unfortunately, JavaScript's `map` doesn't support `Iterators`.

```javascript
range (1) (4)
  .map (double) //=> Error: map is not a function​​
```

Even if we do some sorcery, we can't get it to work...

```javascript
Array.prototype.map.call(range (1) (4), double) //=> []
```

In JavaScript-land, the `Iterator` must be cast to an `Array` first before it can be mapped.

```javascript
Array.prototype.map.call([...range (1) (4)], double) // [2, 4, 6]
//                        ----------------
//                      /
//     cast to an Array

[...range (1) (4)].map(double) //=> [2, 4, 6]
//---------------
//                 \
//                   cast to an Array
```

But with MojiScript, `map` has no problems with `Iterators` and the syntax is identical to mapping over an `Array`.

```javascript
map (double) (range (1) (4)) //=> [2, 4, 6]
```

# Mapping strings

The same syntax is used for mapping chars in a string.

```javascript
const charCode = x => x.charCodeAt(0)

// JavaScript
Array.prototype.map.call('abc', charCode) //=> [97, 98, 99]

// MojiScript
map (charCode) ('abc') //=> [97, 98, 99]
```

# NodeLists

NodeLists are also supported!

```javascript
// JavaScript
document.querySelectorAll('div[id]').map()
//=> Error: document.querySelectorAll(...).map is not a function

// MojiScript
const getId = element => element.getAttribute('id')
const divs = document.querySelectorAll('div[id]')

const ids = map (divs) (getIds)
//=> ['id1', 'id2', 'id3']
```

# Maybe

The `Maybe` type is an excellent alternative to a nullable type. Instead of using null and having to perform null checks, you can use a `Maybe` type in it's place.

**JavaScript:**

```javascript
const upper = string =>
  string == null ? string : string.toUpperCase()

upper(null) //=> null
upper('abc') //=> 'ABC'
```

**MojiScript:**

`Maybe` can eliminate the need for most null checks. Again, the syntax is the same as any other call to `map`.

```javascript
import map from 'mojiscript/list/map'
import Just from 'mojiscript/type/Just'
import Nothing from 'mojiscript/type/Nothing'

const upper = map (string => string.toUpperCase())

upper (Nothing) //=> Nothing
upper (Just ('abc')) //=> Just ('ABC')
```

Some helper methods to easily get you in and out of `Maybes`:

```javascript
import Just from 'mojiscript/type/Just'
import { fromMaybe, fromNullable } from 'mojiscript/type/Maybe'
import Nothing from 'mojiscript/type/Nothing'

fromNullable (null) //=> Nothing
fromNullable ('abc') //=> Just ('abc')

fromMaybe ('') (Nothing) //=> ''
fromMaybe ('') (Just ('abc')) //=> 'abc'
```

The `Maybe` is far to big of a subject to cover here. Fortunately, I have written an entire article on the subject here: [NULL, "The Billion Dollar Mistake", Maybe Just Nothing](https://dev.to/joelnet/null-the-billion-dollar-mistake-maybe-just-nothing-1cak)

# Asynchronous map

MojiScript's `map` also supports asynchronous mapping!

```javascript
const double = x => x * 2

const asyncDouble = num => new Promise(resolve => {
  setTimeout(() => {
    console.log({ num })
    resolve(double(num))
  }, 1000)
})

map (asyncDouble) (range (1) (5))
//=> [2, 4, 6, 8, 10]
```

# Mapping Async Iterables

MojiScript's `map` also support async  iterators!

```javascript
const timeout = seconds =>
  new Promise(resolve => setTimeout(resolve, seconds))

async function* asyncGen() {
  await timeout (1000)
  yield 1
  await timeout (1000)
  yield 2
  await timeout (1000)
  yield 3
}

const double = x => x * 2

const iter = asyncGen();

map (double) (iter)
//=> Promise([ 2, 4, 6 ])
```

# Summary

MojiScript can `map`: `Array`, `Iterators`, `Async Iterators`, `Functors`, and `Strings`.

MojiScript's `map` also supports asynchronous code, which is pretty f'n awesome.

Check out [MojiScript](https://github.com/joelnet/MojiScript). It's pretty awesome! [Hop over to the MojiScript Discord chat and say hi!](https://discord.gg/Gg7ptD5)

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

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