ECMAScript 2019(ES2019) – New Features with Examples

Posted by

And here we are, it’s that time of the year when a new version of ECMAScript is released. What does it actually means ? There is a defined process before a feature can be approved by TC39 committee and go live – be included in the specification.

Every feature goes through the following process:

Stage 0: Ideas/Strawman
Stage 1: Proposals
Stage 2: Drafts
Stage 3: Candidates
Stage 4: Approved

According to this tweet from Mathias Bynens(member of the TC39 committee), the features that made it to Stage 4 the last year and will be included into the specification are:

  1. Array#{flat,flatMap}
  2. Object.fromEntries
  3. String#{trimStart,trimEnd}
  4. Symbol#description
  5. try { } catch {} // optional binding
  6. JSON ⊂ ECMAScript
  7. Well-formed JSON.stringify
  8. Stable Array#sort
  9. Revised Function#toString

We will explore them one by one.

Array#{flat,flatMap}

These two methods are now available in the Array prototype.

flat()

The name “flat” is pretty much self explanatory. This method returns a flattened version of the array it was called on.

Here is an example basic usage:

const arr = [1,2,[1,2],[2,3]];
const flatArr = arr.flat();
console.log(flatArr); // [1,2,1,2,2,3]

The flat method also supports optional argument specifying the depth of flattening. In case of no argument pass, the default value will be 1(depth of 1).

If we call the flat method on an array with level of nesting more than 1, it will flatten only the first level.

Example:

const arr = [1,2,[1,2,[4,5]],[2,3]];
const flatArr = arr.flat();
console.log(flatArr); // [1, 2, 1, 2, [4 5], 2, 3]

The array [4,5] doesn’t get flattened.

If we pass an argument “2” to the method, it will be flattened correctly:

const arr = [1,2,[1,2,[4,5]],[2,3]];
const flatArr = arr.flat(2);
console.log(flatArr); // [1, 2, 1, 2, 4, 5, 2, 3]

What about if we don’t know the depth of the array ? Then, we can use the “Infinity” as an argument. Like this:

const arr = [1,2,[1,2,[4,5,[6,7]]],[2,3]];
const flatArr = arr.flat(Infinity);
console.log(flatArr); // [1, 2, 1, 2, 4, 5, 6, 7, 2, 3]

flatMap()

This method has the same effect/functionality as using the map() and then flat(), i.e. it maps the values to a new ones and then flatten the result. The other difference here is that no argument for depth as the one in flat supported. It’s using depth of 1 as default.

Here is an example and comparison between flatMap and map:

const names = ["John", "Johny", "Peter"];

const mapOnly = names.map((name, idx) => [idx, name]);
const flatMap = names.flatMap((name, idx) => [idx, name]);

console.log(mapOnly); // [[0, "John”],[1[1, "Johny”]2, [2, "Peter”]nsole.log(flatMap); // [0, [0, "John”,1, "Johny”,2, "Peter”]



The callback function structure expected by flatMap is the same as map.

Object.fromEntries

This method is the opposite of Object.entries()

While the Object.entries() transform object entries to an array of [key, value][key, value]Object.fromEntries() transform a list of [key, value][key, value]an object.

It works on both maps and simple nested arrays:

const map = new Map().set("id", 1).set("name", "John");
const arr = [["id", 1], [["id", 1]Jo["name", "John"]pObj  = Object.fromEntries(map);
const arrObj = Object.fromEntries(arr);

console.log(mapObj); // {id: 1, name: ‘John’}
console.log(arrObj); // {id: 1, name: ‘John’}

String#{trimStart,trimEnd}

Many of the browsers already support trimRight and trimLeft, but in order to be consistent with the padStart and padLeft, a decision to create trimStart and trimEnd was made.

Both methods are attached to the prototype of String.

An example how to use them:

const exampleStr = "      first class js     ";

const trimStart = exampleStr.trimStart();
const trimEnd = exampleStr.trimEnd();

console.log(trimStart); // "first class js     "
console.log(trimEnd);   // "      first class js"

Symbol#description

A new read-only property was added to the Symbol objects. It’s optional and is returning the description of the Symbol.

An example:

const mySymbol = Symbol(“first”);

const description = mySymbol.description;

console.log(description); // “first”

try { } catch {} // optional binding

Optional catch binding was also introduced.

Before this proposal, we were forced to bind exception variable for the catch clause, like this:

try {
 // do something
} catch(err) {
 // throw custom error, i.e. don’t use the err variable
}

From now on, we are able to omit the exception variable and do the following:

try {
 // do something
} catch {
 // throw custom error
}

JSON ⊂ ECMAScript

The line separator (U+2028) and paragraph separator (U+2029) symbols were not allowed in string literal.

Previously, these were treated as line terminators and were causing SyntaxError. This solution extends the ES strings, so the mentioned above symbols be accepted.

// Produces invalid string before ES2019
eval('"\u2028"');
eval('"\u2029”’);
// Valid in ES2019
eval('"\u2028"');
eval('"\u2029”’);

Well-formed JSON.stringify

Before ES2019, the calling ofJSON.stringify() with surrogate UTF-8 code(U+D800 to U+DFFF) was returning a single UTF-16 code unit, while now it represent them as strings. This way they can be transformed back to their original representation with JSON.parse();

// Before ES2019
JSON.stringify('\uD800'); // ""
// Now 
JSON.stringify('\uD800'); // "\ud800"

Stable Array#sort

According to this tweet from Mathias Bynens, the sort method for arrays is now stable. It’s using the stable TimSort algorithm for arrays over 10 elements instead of the unstable QuickSort.

Array.prototype.sort is now stable in @v8js v7.0 / Chrome 70!

Previously, V8 used an unstable QuickSort for arrays with more than 10 elements. Now, we use the stable TimSort algorithm.

Mathias Bynens

You can check the tweet for a demo.

Revised Function#toString

The available toString method in the functions prototype is nothing new. It just return a string representing the function code. But what is the difference now ?

Previously(before ES2019) this method was returning the code with some modifications like stripping the comments, removing some whitespaces and etc.

Now, the code is returned as it was declared – with all the whitespaces, comments and formating.

Before:
function /* this is comment */ testFunc() {}

console.log(testFunc.toString()); // function testFunc() {}

Now:
function /* this is comment */ testFunc() {}

console.log(testFunc.toString()); // function /* this is comment */ testFunc() {}

Conclusion

Comparing to ES2015, the new version of ECMAScript doesn’t introduce so many new changes. However, we can agree that all of them are really useful and will take their place in the future of the Javascript development.

If you are curious what we can expect from the community or just want to be up to date with the latest features, you can check the TC39 proposals, available publicly on GitHub.