What’s New in ES2019?


ES2019 or ES10 is the 2019 version of JavaScript. After the major 2015 update, JavaScript has been evolving every year. Developers get a small set of useful features, that helps us balance between innovation and stability.

You can also follow the evolution of JavaScript in this blog, because the first article was published back in 2015. It is now time that we examine the ES2019 updates from a practical point of view. As usual, don't expect a lengthy description of theoretical edge cases. This article rather doubles down on practical use cases.

JavaScript compatibility table

If you want to see a complete list of updates for each edition of JavaScript, check out this compatibility table. When I looked at the updates in my latest Google Chrome, I saw that most of the tests passed even for the proposed ES2020 version.

Be aware that your code may have to support multiple browsers. Therefore, do consider using polyfills in your application.

Let's explore the list of ES2019 features one by one:

1. Object.fromEntries

Recall Object.entries from ES2015:

It makes perfect sense to provide the inverse transformation:

Besides using arrays, you can also create objects from maps:

2. String trimming

Suppose a string is given, where the content to be inserted is surrounded by whitespace characters (newline, tab, space etc.):

In earlier versions of JavaScript, trimming was already possible:

In ES2019, it is also possible to trim just the left or just the right side of the string.

  • trimStart and trimLeft come handy when we have to insert text (including the trailing whitespaces at the end) into a specific position.
  • trimEnd and trimRight come handy when we have to insert something right after the end of the text (for instance, displaying HTML markup before an = $0 marker highlighting that the DOM element is available in the console).
  • also notice that the ES2019 trimStart and trimEnd methods remove padding added by the ES padStart and padEnd:

3. Array.prototype.flat

The flat method of arrays flattens the array in the following way: if A is an element of our array, and A is an array, then A is substituted by ...A.

becomes

which becomes

The flat method may take an optional numeric argument. If this argument is 1, flattening happens on one level. In other words, A.flat(1) is equivalent with A.flat().

If an argument to flat is supplied, this argument has to be at least 1 for flattening to happen:

  • [[1]].flat(0) stays [[1]],
  • [[1]].flat(1) becomes [1].

When flat has an integer argument greater than 1, flattening becomes a recursive operation, where on each recursion level, the argument of flat decreases by 1.

A special case of flat offers flattening in infinitely long depth:

This special case is rarely used, as developers are supposed to know their data structures such that they already know how many levels they need to flatten. Most often the time in practice, one level of flattening is desirable, because we typically don't retrieve nestad multidimensional arrays from APIs.

Exercise: Suppose the state of a TicTacToe game is given in the form of a two dimensional array. Transform the game board to a string of 9 characters to simplify calculations.

Expected output:

Solution:

4. Array.prototype.flatMap

This section is easy. Suppose an array A, and a function transformer is given.

A.flatMap(transformer) is defined as A.map(transformer).flat().

First we map each element using the transformer function, then we flatten the array. Note that flattening is on one level.

One remark on the naming. You may wonder why this function is called flatMap if we use map first and flat second. Why isn't it mapFlat? There are multiple reasons.

First, flatMap is a well known function in functional programming. Lodash has it, as well as RxJs.

Second, notice the chained notation A.map(f).flat() turns everything upside-down. If we just had functions and not chained array methods, then the expression would look like this: flat(map(A, f)). This natural order of function applications is defined by the rules of function composition.

Exercise: Suppose you have a list of formula one teams.

Create a JavaScript expression that returns an array of drivers in any order.

Solution:

We could create a loop and concatenate the values of the drivers of each team. Or, we could also map the value of each team onto their list of drivers (plucking), and then concatenate the list.

5. Optional catch binding

How often have you written a try-catch code segment, where you didn't make use of the error object provided by the catch block?

I know e is just one unnecessary character in the code, but creating and never using a variable looks quite disturbing. ES2019 puts an end to this small issue by making the error object binding optional:

6. Symbol.prototype.description

The description property of symbols returns their description. This description is read only.

In the unlikely case you used Symbol keys in an object, and you wanted to print debugging or logging information on this key, then the description property may come handy.

For presentation purposes, using strings instead of symbols is recommended.

Even though Symbol descriptions are not meant to be used to determine if two symbols are the same, the descriptions can still be used in the code, as they store optional string data.

7. Function.prototype.toString

This section is so obvious that it's sufficient to illustrate it in Charlie Chaplin style.

Use cases: documentation, debugging.

8. Well formed JSON.stringify

This is a typical update that you either already know and appreciate, or it does not bother you at all.

Please find the details on the tc39/proposal-well-formed-stringify repository. The idea is to prevent formatting errors with Unicode strings.

9. Stable Array.sort

When sorting an array, some elements of the array may be equal. The order of these equal elements is preserved by the sorting algorithm.

This is yet another edge case that helps you make rendering slightly less glitchy when sorting a table for instance based on different columns ascending and descending.

Example:

Assuming two elements are equal (i.e. the comparator returns zero), the elements are now guaranteed to stay in their original order:

Same holds for the years:

This is another edge case that might prevent you from unstable rows rendered by your application or returned by your API in extreme cases.

10. JSON superset

Unless you have worried about it in the past, don't worry about it. The specification may be worth a short read.

This update is mostly about standardization and specifying exact definitions based on which the language specification can be well described and regulated.

For a software engineer, this only means that in the very unlikely case you have problem with the line separator ('\u2028') or page separator ('\u2029') characters, make sure you uniformly treat them as whitespace characters just like a space, a tab, or a newline character.

That's all folks

This was 2019, a few useful updates, and a few edge cases. JavaScript has not been turned upside-down this year.

It is still worth keeping up-to-date with how JavaScript evolves. I also suggest checking how languages that transpile to JavaScript evolve. For instance, if you check the new features of TypeScript, chances are, that you will see some of them in JavaScript one day.

If you liked the exercises, and you would like to prepare for your coding interview, check out my book, ES6 in Practice.

If you would like to get notified when a new article comes out, don't hesitate to sign up below.

Learn ES6 in Practice

Sign up below to access an ES6 course with many exercises and reference solutions.