When you read about Javascript you will also come across the terms like ES2017, ES2018 and ECMAScript.
What are these and what do they mean? Why call it ECMAScript when we also refer it as JavaScript? Let’s have a quick look into it.

  • ECMAScript: ECMAScript is a standard for creating a scripting language based on a variety of technologies, the most popular of them are JavaScript (Netscape), JScript (Microsoft) and ActionScript(Flash). It was presented by ECMA International (Switzerland) and the specification is defined in ECMA-262.
  • Javascript: It is a scripting language that complies with the specs provided by ECMAScript.

Now that we are clear about the names, let’s dive into the features of ES2017.
ES2017 brings Async Functions, Shared Memory and Atomics along with some more language and library enhancements and bug fixes.

1. Async Functions

To solve the problem of asynchronous code and the callback hell problem, Promises were introduced in ES2015. However, they had syntax complexity and it was realized that we need a better solution to deal with it.

Here’s an example to get JSON data and parse it using Promises:

const getProductsData = () => {
        return fetch('/products.json') // get products list   
            .then(response => response.json()) // parse JSON   
            .then(products => products[0]) // pick first product   
            .then(products => fetch(`/products/${product.name}`)) // get products data  
            .then(productResponse => response.json()) // parse JSON}
        getproductsData();

The same code can be written in a better way using the Async/Await function:

const getproductsData = async () => {
            const response = await fetch('/products.json')
            const products = await response.json()
            const products = products[0]
            // get products data
            const productsResponse = await fetch(`/products/${product.name}`)
const productsData = await product.json() // parse JSON  return productsData
}
            getproductsData();

2. Shared Memory and Atomics

WebWorkers are used to run the script in the background thread, it can perform task apart from the main thread without interfering with the user interface. It can also be used to create multi-threaded programs in the browser.WebWorkers and the main thread share data among them by sending and receiving messages. The data is sent using the postMessage( ) method and they respond via the onMessage( ) event handler.

In ES2017 you can create a shared memory between the WebWorkers and the main thread using SharedArrayBuffer.A new global object Atomics has been introduced which provides a number of new atomic operations as static methods.

For a detailed understanding of this you can check here.

3. Trailing Commas

This is a syntax update which allows you to have trailing commas in function call or function declaration. This change will be helpful for the developers when using git as to add one parameter to a function list they do not have to edit two lines of code.

const testFunc => (
    param1,
    param2,
    param3,
    param4, ) { // trailing comma allowed here!
    /*you
         function body
     here*/
}

4. Object.values

Object.values returns an array of the values of the own object properties.

const dummyObject = {
    foo: ‘fooName’,
    bar: 999
};
Object.values(dummyObject); // returns [‘fooName’,999]

This works with arrays too,

const dummyArray = [‘fooName’, 999];
Object.values(dummyArray); // returns [‘fooName’,999]

5. Object.entries

Object.entries returns an array of object own properties as an array of [key, value] pairs.

const dummyObject = {
    foo: ‘fooName’,
    bar: 999
};
Object.entries(dummyObject); // returns [[‘foo’,’fooName’], [‘bar’,999]]

This works with arrays too,

Object.entries(dummyArray); // returns [[‘0’,’fooName’], [‘1’,999]]

6. Object.getOwnPropertyDescriptors

The reason for introducing this method is to overcome the shallow behaviour of a copied or duplicate object. Prior to this we have used Object.assign( ), which does not copy the non default attributes. In other words, it directly accesses the properties and symbols instead of the descriptors. This could be a problem when we are working with complex objects and classes prototypes.

Object.getOwnPropertyDescriptors(obj) accepts an object, and returns an object with the set of descriptors.

Here’s a quick example for your understanding:

const product1 = {
    set name(newName) {
        console.log(newName);
        console.log("bar");
    }
};
const product2 = {};
Object.assign(product2, product1);
const product3 = {};
Object.defineProperties(product3, Object.getOwnPropertyDescriptors(product1));
product1.name = “foo1”; //returns foo1 bar
product2.name = “foo2”; //skips the setter function
product3.name = “foo3”; //returns foo3 bar

7. String Padding

String Padding feature gives the user a better control over the string and its manipulation. ES2017 introduces primitive methods like padStart( ), padEnd( ).

padStart( ) and padEnd( ) is used to add spaces(padding) or characters before or after a string.

console.log('foo'.padStart(10));         //returns "       foo"
console.log('foo'.padStart(10, "bar"));  //returns "barbarbfoo"
console.log('foo'.padStart(6,"123465")); //returns "123foo"
console.log('foo'.padStart(8, "0"));     //returns "00000foo"
console.log('foo'.padStart(1));          //returns "foo"
console.log('foo'.padEnd(10));         //returns "foo       "
console.log('foo'.padEnd(10, "bar"));  //returns "foobarbarb"
console.log('foo'.padEnd(6,"123465")); //returns "foo123"
console.log('foo'.padEnd(8, "0"));     //returns "foo00000"
console.log('foo'.padEnd(1));          //returns "foo"

Now, let’s dive into the features of ES2018 and see what we have in store for us.

ES2018 introduces features like Object Rest/Spread Properties, Asynchronous Iteration, Promise.prototype.finally() and some RegExp related enhancements.

1. Object Rest/Spread Properties

The notion of the Rest property was previously introduced in ES2015 for arrays, in ES2018 the similar feature has been introduced again but for objects.

A quick example:

const { x, y, ...others } = { x: 1, y: 2, a: 3, b: 4, c: 5 }
console.log(x); //returns 1
console.log(y); //returns 2
console.log(others); //returns {a: 3, b: 4, c: 5}

2. Asynchronous Iteration

Asynchronous iterators are similar to the regular iterators, just that the next( ) function returns a promise value for a {value, done} pair.

Let’s have a look at the following example:

function asyncIterator() {
    const array = [1, 2, 3];
    return {
        next: function() {
            if (array.length) {
                return Promise.resolve({
                    value: array.shift(),
                    done: false
                });
            } else {
                return Promise.resolve({
                    done: true
                });
            }
        }
    };
}

var iterator = asyncIterator();

(async function() {
    await iterator.next().then(console.log); // { value: 1, done: false }
    await iterator.next().then(console.log); // { value: 2, done: false }
    await iterator.next().then(console.log); // { value: 3, done: false }
    await iterator.next().then(console.log); // { done: true }
})();

a promise need to be returned because, when the iterator returns the values of value and done are unknown.
For customizing an object as an async iterator, [Symbol.asyncIterator] is introduced.

var asyncIterable = {
    [Symbol.asyncIterator]: asyncIterator
};

(async function() {
    for await (const item of asyncIterable) {
        console.log(item); //returns 1 2 3
    }
})();

In the example above the for-wait-of loops receives the data from the [Symbol.asyncIterator] method. Everytime next( ) method is called, the for-wait-of loop implicitly waits for the promise to be resolved. The promise is then returned by the iterator method.

4. Promise.prototype.finally( )

Once a promise is satisfied, the .then( ) blocks are called. If anything fails, the .then( ) blocks are skipped and the catch( ) block is executed.
The finally( ) block is executed despite the successful execution of the promise.

fetch('http://justadummyurl/endpoint')
    .then(result => {
        //your code here
    })
    .catch(error => {
        console.error(error)
    })
    .finally(() => {
        console.log('finished')
    })

4. Regular Expressions related enhancements

  • Named capturing groups

In ES2018 a capture group can be set to a name, than assigning a slot in the result array:

Example:

const RE_DATE = /(?<year>[0-9]{4})-(?<month>[0-9]{2})-(?<day>[0-9]{2})/;

const matchObj = RE_DATE.exec('2018-12-25');
const year = matchObj.groups.year; //returns 2018
const month = matchObj.groups.month; //returns 12
const day = matchObj.groups.day; //returns 25
  • Lookbehind Assertions

Lookbehinds, a new feature, you use ?<= to match a string that’s followed by a specific substring:

/(?<=Hello) World/.test('Hello World is common!') //returns true
  • Unicode Property Escapes

In ES2018, Unicode property escapes, denoted by \p{…}, are available in regular expressions when the u flag is set. For matching any Unicode number, you can simply use \p{…}.

This new feature extends this concept to all Unicode characters introducing \p{} and is negation \P{}.

const str = '𝟠';
console.log(/\p{Number}/u.test(str));
  • The s (dotAll) flag for regular expressions

The s flag, short for single line, causes the . to match new line characters as well. Without it, the dot matches regular characters but not the new line:

/hi.welcome/.test('hi\nwelcome') //false
/hi.welcome/s.test('hi\nwelcome') // true