Skip to main content

JavaScript as a language has been maturing at a steady pace in the past decade with the evolution of ECMAScript. The current version was released in June 2018, ES2018 and the upcoming version brings several new additions to the language which we’ll cover in this post.

Before that, it can be useful to know how new features are being added to the language through the additions to the ECMAScript standard.

ECMAScript proposals

The Technical Committee 39, TC39, is responsible for reviewing and adopting changes to the existing version of the ECMAScript standard. The process takes the form of 5 stages of maturity after which a new feature is included in the standard.

  • Stage 0: Strawman
  • Stage 1: Proposal
  • Stage 2: Draft
  • Stage 3: Candidate
  • Stage 4: Finished

There is no guarantee that a feature in Stage 3 will be included in the standard, but generally, JavaScript engine implementations like V8 (Chrome, Node.js, Opera), SpiderMonkey (Firefox) and Chakra (Microsoft Edge) tend to add some features with experimental support so that developers can test and provide feedback.

ES2019 finished features

At the time of writing this post, there have been several finished features, you can check the full list in the TC39 proposal repository.

  • Array.prototype.{flat, flatMap}
  • Object.fromEntries()
  • String.prototype.{trimStart, trimEnd}
  • Symbol.prototype.description
  • Subsume JSON
  • Optional catch binding
  • Well-formed JSON.stringify()
  • Function.prototype.toString()

Array.prototype.{flat, flatMap}

The new array instance method, flat(), flattens an array up to a given value, it takes an optional depth argument which can be set to Infinity to run recursively until the array is single dimensional.

const nestedArray = ["a", ["b", "c"], ["d", ["e", ["f"]]]];

// using flat() on a multidimensional array
nestedArray.flat();
["a", "b", "c", "d", ["e", ["f"]]]

// using flat() with an argument
nestedArray.flat(2);
["a", "b", "c", "d", "e", ["f"]]

// using flat() with Infinity as argument
nestedArray.flat(Infinity);
["a", "b", "c", "d", "e", "f"]

flatMap() is similar to the existing map() method, but the callback can return an array and the end result will be a single dimensional array instead of nesting arrays.

const scatteredArray = ["a b c", "d", "e f", "g"];

// map() results in nested arrays
scatteredArray.map( chunk => chunk.split(" "));
[["a", "b", "c" ], [ "d" ], [ "e", "f" ], [ "g" ]]

// flatMap() concatenates the returned arrays together
scatteredArray.flatMap( chunk => chunk.split(" "));
["a", "b", "c", "d", "e", "f", "g"]

Object.fromEntries()

Objects have an entries() method since ES2017, it returns an array key-value pairs of the object’s properties. The fromEntries() method does the reverse and returns an object from an array of properties.

If we use both methods on an object the cloned object will be copied by reference.

const person = { name: "John", age: 30, country: "UK" }

// using Object.entries and assigning it to a new object
const entries = Object.entries(person)
[["name", "John" ], [ "age", 30 ], [ "country, "UK" ]]

// using the new Object.fromEntries
const newPerson = Object.fromEntries(entries)
{ name: "John", age: 30, country: "UK" }

// the new object is a shallow copy
person !== newPerson
true

String.prototype.{trimStart, trimEnd}

trimStart() returns a string with removed whitespaces from the start of the original string, while trimEnd() removes whitespaces from the end.

const str = "   blank spaces   ";

// trimStart() usage
str.trimStart();
"blank spaces   "

// trimEnd() usage
str.trimEnd();
"   blank spaces"

Symbol.prototype.description

When creating a symbol, you can now retrieve its description property instead of using toString() on the object.

const symbol = Symbol("This is the symbol description")

// retrieving the description property
symbol.description;
"This is the symbol description"

Subsume JSON

This proposal solves an issue of inconsistency between a JSON and an ECMAScript JSON, which by specification should be a superset of a JSON.

JSON strings currently accept unescaped U+2028 and U+2029 characters, while ECMAScript strings don’t. With this extension of the ECMAScript JSON, this gap will be patched.

Optional catch binding

In previous versions of ECMAScript, we had to implement a catch binding even if we never had to use it.

try {
  // ...
} catch (error) {
  // handle error
}

With this addition, we can now simply omit it.

try {
  // ...
} catch {
  // handle error
}

Well-formed JSON.stringify()

This fixes the JSON.stringify() output when it processes surrogate UTF-8 code points (U+D800 to U+DFFF). Before this change calling JSON.stringify() would return a malformed Unicode character (a “�”).

Now those surrogate code points can be safely represented as strings using JSON.stringify() and transformed back into their original representation using JSON.parse().

Function.prototype.toString()

ES2019 introduces a change to the toString instance method of functions. Now the returned value will be exactly as defined, without stripping whitespaces and comments.

function /* this is foo */ foo () {}

// previous behavior of toString()
foo.toString()
"function foo () {}"

// proposal behavior
foo.toString()
"function /* this is foo */ foo () {}"

Upcoming candidate features

The following list contains all current candidate features which have reached Stage 3 and will most likely be included in the specification in the future.