Advanced functionality with functions in JavaScript
Tags: javascript, codenewbie, webdev
Published: 2021-06-01 13:29:07

Right since 2015, EcmaScript6 has brought many advancements in JavaScript coding practices. A lot of modern stuff is included in JavaScript, which enhances the coding experience and makes writing code easier. Some of the features include spread operator, maps, sets, generators, and a lot more. Let’s explore these features in greater detail.


## Spread operator
Spread operators is a new function in JavaScript ES6 version. The spread operator allows an iterable to expand in places where zero or more arguments are expected. It is represented using the `...` syntax. It makes shallow copies of objects in JavaScript. You can use the spread operator to concatenate two or more arrays, expand them, calculate the sum of all elements or copy an array. 

Consider the following piece of code, 

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

function x(){
  console.log(arr);
}
x.apply(null, arr);
```

Here, you need to use the `apply`  function to print it in the same way. Using the spread operator, the same functionality can be achieved with:

```
function x(){
  console.log(...arr);
}
```

## Closures
The closure is a function bind with its lexical environment. In simpler terms, a closure is a function inside a function that returns some value.
Consider this simple example,

```
function outerFunc(){
  let val = 2;
  function innerFunc(){
    console.log(val);
  }
  innerFunc();
}  
outerFunc();
```

The function `outerFunc` creates a local variable called `val` and there's a function named `innerFunc` inside `outerFunc`. Since inner functions have access to the outer functions, the `innerFunc` has access to the variables of  `outerFunc` as well.

So, when you try to print the value of variable `val`, it will give you output as 2. 


## Iterators and generators
Iterators and generators are two different concepts but they're used in similar ways. They're used to iterate through arrays and objects in JavaScript. 
**Iterators** are like advanced loops that can be paused and **Generators** are functions that can be paused and can return multiple values.

### Iterators
Here is an example of an iterator

```
function fruitIter(fruits){
  let index = 0;
  return {
    next: function(){
      return index < fruits.length ? { value: fruits[index++], done: false } : {done: true}
    }
  }
}

const fruitsArray = ["Mango", "Banana", "Grapes"];

const fruits = fruitIter(fruitsArray);
console.log(fruits.next().value); // output: Mango
```

When the array `fruitsArray` is passed in `fruitIter` function, the index is initialized to 0, then it goes into the next function and checks whether the index is greater than `fruitArray`’s length and returns an object while incrementing the value of the index. 

This is how iterators work. If we call the function using `fruit` iterator again, it will print its value (Banana). If you're done iterating through `fruitsArray`, the status `done` will change to false and the value will be undefined. 


#### Generators
Generators are similar to Iterators but they return multiple values. These values are called yield values. Generator functions are written using the `function*` syntax. `*` denotes that it is not a normal function but a generator.
Here is an example of generators:
```
function* printFruits(){

  yield "Mango";
  yield "Banana";
  yield: "Grapes";
}

 const fruit = printFruits();
 console.log(fruit.next()); // Output: { value: "Fruit", done: false }
```
In this example, yield is the iterator, and when you call the function sayFruit and print fruit.next(), it gives you an object where you get the value and the `done` status which denotes whether all values are iterated through or not.



## Maps 
A map is an object that holds key-value pairs. Any object reference type or a primitive can be used as a key or value.

**How can you create maps?**
```
const mp1 = new Map();
const key1 = "String",
      key2 = {},
      key3 = function(){}
      
 // setting map values by key
 mp1.set(key1, "Key 1");
 mp1.set(key2, "Key 2");
 mp1.set(key3, "Key 3");
 
```

You can create a map using the `new Map()` syntax. The key can be of any type: String, Number, function, or object. We use the `set` keyword to store key-value pairs into the map.

**Other functionality with maps**
```
// Get values by keys
console.log(mp1.get(key1);  // Key1

// Get size
console.log(mp1.size) // 3
```
**Iterating through maps**

```
// using for loop
for(let [key, value]of mp1){
    console.log(`${key} -> ${value}`);
    
 // iterating through keys
 for(let key in mp1.keys()){
    console.log(key);
 }
}

 // iterating through values
 for(let value in mp1.values()){
    console.log(value);
 }
}

```

## Sets
A set is an array that holds unique values in it. You can add anything inside a set: an object, number, boolean, etc.

```
const s = new Set();

// add values
s.add(2);
s.add(true);
s.add("String");
s.add({name: "sheep"});

// get count
console.log(s.size);

// delete an item
s.delete(2);

```
**Check for value in set**
```
console.log(s.has(2)); // true
console.log(s.has(100)); //false
console.log(s.has({name: "sheep"})); // false

```

In the above code, if you check whether object `{name: "sheep"}` exists in the list, then it will return false even though it does exist in the set. This is because object type is nonprimitive in JavaScript. Although both these objects are the same, they point to different memory locations. Hence, that statement returns a false value.

**Iterating through sets**

```
for(let x in s){
  console.log(x);
}
```