Great New Features in ES2018 You May Have Missed
Tags: javascript, webdev, tutorial, beginners
Published: 2020-01-12 00:15:46

**Subscribe to my email list now at http://jauyeung.net/subscribe/**

**Follow me on Twitter at https://twitter.com/AuMayeung**

**Many more articles at https://medium.com/@hohanga**

Ever since ES2015 was released, which was a great leap forward in itself, JavaScript has been improving at a fast pace. Every year since then, new features have been added to JavaScript specifications.

Features like new syntax and new methods for building in JavaScript have been added consistently. In ES2016 and 2017, The `Object` object had methods like `Object.values` and `Object.entries` added.

String methods like `padStart` and `padEnd` were added in ES2017. `async` and `await`, which is a shorthand syntax for chaining promises, were also added in ES2017.

The `includes` methods for arrays were added in ES2016. ES2018 was another release with lots of new features. With ES2018, the spread syntax is now available for object literals. Rest parameters were also added.

The `for await...of` loop, which is a loop syntax iterating through promises sequentially, was also added. The `SharedArrayBuffer` object was added for representing raw binary data that cannot become detached.

A `finally` function was also added to the `Promise` object.

* * *

Spread Operator in Objects
==========================

The spread syntax works by copying the values of the original array, and then inserting them into another array or putting them in the order they appeared in the array as the list of arguments in a function in the same order.

When the spread operator is used with objects, the key-value pairs appear in the same order they appeared in the original object.

With ES2018, the spread operator works with object literals. Then key-value pairs of an object can be inserted into another object with the spread operator.

If there are two objects with the same key that the spread operator is applied to in the same object, the one that’s inserted later will overwrite the one that’s inserted earlier.

For example, if we have the following:

```javascript
let obj1 = {foo: 'bar', a: 1};  
let obj2 = {foo: 'baz', b: 1};  
let obj3 = {...obj1, ...obj2 }
```

Then we get `{foo: “baz”, a: 1, b: 1}` as the value of `obj3` because `obj1` is spread before `obj2`. They both have `foo` as a key in the object.

First `foo: 'bar'` is inserted by the spread operator to `obj3`. Then `foo: 'baz'` overwrites the value of `foo` after `obj2` is merged in since it has the same key, `foo`, but was inserted later.

This is great for merging objects as we don’t have to loop through the keys and put in the values, which is much more than one line of code.

One thing to note is that we can’t mix the spread operator between regular objects and iterable objects. For example, we will get `TypeError` if we write the following:

```javascript
let obj = {foo: 'bar'};  
let array = [...obj];
```

* * *

Rest Operator
=============

The rest operator is a JavaScript operator where we can store an indefinite number of arguments in a function as an array. It looks exactly like the spread operator, which lets us spread entries of an array or a list of key-value pairs of an object into another object.

For example, if we have a function that has a long list of arguments, we can use the rest operator to shorten the list of parameters in a function.

The rest operator is used with the following syntax:

```javascript
const fn = (a,b,..restOfTheArgs) => {...}
```

Where `restOfTheArgs` is an array with the list of arguments other than the first two.

For example, if we want to write a `sum` function that takes an indefinite list of numbers as arguments and sum up the numbers, we can write:

```javascript
const sum = (a,b,...otherNums) => {  
  return a + b + otherNums.reduce((x,y)=>x+y, 0);  
}
```

As we can see, this is very handy for functions that have any list of arguments. Before we had this, we had to use the `arguments` object available in functions to get a list of arguments. This is not ideal as we allow them to pass in anything into the arguments.

With the rest operator, we have the best of both worlds. We can have some fixed parameters, while the rest stay flexible. This makes functions more flexible than functions with a fixed number of parameters, while having some flexibility of functions that take an indefinite number of arguments.

The `arguments` object has all the arguments of the function. Also, it’s not a real array, so array functions aren’t available to them. It’s just an object with indexes and keys to denote the argument’s positions.

Methods like [sort](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort), [map](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map), [forEach](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/forEach), or [pop](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/pop) cannot be run on the `argument`’s object. It also has other properties. This creates confusion for programmers. The arguments that are converted to an array with the rest operator do not have these issues, as they are real arrays.

To call the `sum` function we wrote, we can write:

```javascript
const result = sum(1,2,3,4,5,6,7,8,9,10);
```

The `result` will be 55, since we summed up all the arguments together. `otherNums` is an array with all the numbers other than 1 and 2.

We can also use the rest operator to destructure a list of arguments into a list of variables. This means that we can convert a list of parameters into an array with the spread operator, and then decompose the array of arguments into a list of variables.

This is very useful as we can get the entries of the array that’s operated on by the rest operator and convert them to named variables. For example, we can write:

```javascript
const sum = (a,b,...[c,d,e])=> a+b+c+d+e;
```

This way, we can use the rest operator, but limit the number of arguments that your function accepts. We take the function parameters `a` and `b`, and we also take `c`, `d`, and `e` as parameters.

However, it’s probably clearer without using the rest operator since all the parameters are fixed, we can just list the parameters directly.

* * *

`for await...of`
================

The `for await...of` loop allows us to create a loop that iterates over a list of promises as well as over the entries of a normal iterables.

It works with iterable objects like arrays, string, `argument` object, `NodeList` object, `TypedArray`, `Map`, `Set`, and user-defined synchronous and asynchronous iterable objects.

To use it, we write:

```javascript
for await (let variable of iterable) {  
  // run code on variable
}
```

The `variable` may be declared with `const`, `let`, or `var`, and the iterable is the iterable objects that we are iterating over. We can iterate over asynchronous iterable objects like the following:

```javascript
const asynNums = {  
  [Symbol.asyncIterator]() {  
    return {  
      i: 6,  
      next() {  
        if (this.i < 20) {  
          return Promise.resolve({  
            value: this.i++,  
            done: false  
          });  
        }
        return Promise.resolve({  
          done: true  
        });  
      }  
    };  
  }  
};

(async () => {  
  for await (let num of asynNums) {  
    console.log(num);  
  }  
})();
```

We should see 6 to 19 logged. It also works with async generators:

```javascript
async function* asynNumGenerator() {  
  var i = 6;  
  while (i < 20) {  
    yield i++;  
  }  
}

(async () => {  
  for await (let num of asynNumGenerator()) {  
    console.log(num);  
  }  
})();
```

We should see the same thing logged. It also works great with promises:

```javascript
const arr = Array.from({  
  length: 20  
}, (v, i) => i)let promises = [];

for (let num of arr) {  
  const promise = new Promise((resolve, reject) => {  
    setTimeout(() => {  
      resolve(num);  
    }, 100)  
  })  
  promises.push(promise);  
}

(async () => {  
  for await (let num of promises) {  
    console.log(num);  
  }  
})();
```

As we can see, if we run the code above, we should see 0 to 19 logged sequentially, which means that promises were iterated through in sequence. This is very handy as we never have anything that can iterate through asynchronous code before this loop syntax was introduced.

* * *

Promise.finally()
=================

The `finally` function is added to the `Promise` object which runs when the promise is settled. That means it runs whenever the promise is fulfilled or rejected.

It takes a callback function that runs whenever the promise is settled. This lets us run code regardless of how a promise ends. Also, this means that we no longer have to duplicate code in the callbacks for `then` and `catch` functions.

To use the `finally` function, we use it as the following:

```javascript
promise  
.finally(()=>{  
  // run code that when promise is settled  
})
```

The `finally` is useful is we want to run code whenever a promise ends like cleanup code or processing after the code ends.

It’s very similar to calling `.then(onFinally, onFinally)`. However, we do not have to declare it twice to make a variable for it and pass it in twice. The callback for the `finally` function doesn’t take any argument, as there’s no way to determine the status of the promise beforehand.

It’s used for cases when we don’t know what will happen to the promise, so there’s no need to provide any argument. If a promise is fulfilled then the resolved value will be intact after calling the `finally` function.

For example, if we have:

```javascript
Promise.resolve(3).then(() => {}, () => {})
```

This will resolve to `undefined`, but if we have:

```javascript
Promise.resolve(3).finally(() => {})
```

The code above will resolve to 3. Similarly, if the promise if rejected, we get:

```javascript
Promise.reject(5).finally(() => {})
```

This will be rejected with the value 5.

* * *

SharedArrayBuffer
=================

The `SharedArrayBuffer` is an object that’s used to represent a fixed-length raw binary data buffer.

It’s similar to the `ArrayBuffer` object, but we can use it to create views on shared memory. It can’t become detached, unlike an `ArrayBuffer`. The constructor of it takes the length of the buffer as an argument.

The length is the size in byte for the array buffer to create. It returns a `SharedArrayBuffer` of the specified size with contents initialized to 0.

Shared memory can be created and updated by multiple workers on the main thread. However, this may take a while until the changes are propagated to all contexts.

* * *

Conclusion
==========

With ES2018, we have more handy features to help developers develop JavaScript apps.

The highlights include the spread operator for objects, which let us copy key-value pairs to other objects and the rest operator to let us pass optional arguments.

The `for await...of` loop lets us iterate through collections of asynchronous code which could never easily be done before.