ES2019 was recently finalized, which means JavaScript has several new language features to learn. These features are now available in Chrome 73:

As of @v8js v7.3 / Chrome 73, all of these ES2019 features are available by default. Enjoy! https://t.co/vtvx8VTRYw — V8 (@v8js) January 29, 2019

Unfortunately there's no version of Node.js at the time of this writing that uses V8 7.3, the current Node.js 12 nightly build still uses V8 7.1. However, V8 v7.0 has most of the ES2019 feature set, see the list below. For the purposes of this article we'll use Node.js 11.6 (V8 v7.0.276).

Array#flat() and Array#flatMap()

The functions responsible for the infamous smoosh-gate controversy have finally landed in ES2019. Thankfully, we don't have to write smooshMap() or componentDidSmoosh() . The flat() and flatMap() functions are available in Chrome 69 / V8 6.9, so you need Node.js 11.

Array#flat() is analogous to Lodash's _.flattenDepth() function. The flat() function takes an array of arrays and "flattens" the nested arrays into the top-level array.

[[ 1 , 2 ], [ 3 , 4 ], [ 5 , 6 ]].flat();

By default, flat() only flattens one level deep:

[[[ 1 , 2 ]], [[ 3 , 4 ]], [[ 5 , 6 ]]].flat();

However, flat() takes a depth argument that specifies how many levels down you want to flatten.

[[[ 1 , 2 ]], [[ 3 , 4 ]], [[ 5 , 6 ]]].flat( 2 );

The new flatMap() function is equivalent to calling map() followed by flat() . This is handy if your map() returns an array.

const oddNumbers = [ 1 , 3 , 5 , 7 , 9 ]; const allNumbers = oddNumbers.flatMap(num => ([num, num + 1 ]));

Since the callback parameter to flatMap() above returns an array, flatMap() flattens out the array. The above is equivalent to:

const allNumbers = oddNumbers.map(num => ([num, num + 1 ])).flat();

One neat trick with flatMap() is that you can do both filter() and map() in one step. You can filter out an element by returning an empty array [] from your flatMap() callback.

const oddNumbers = allNumbers.flatMap(num => num % 2 === 0 ? [] : num);

Object.fromEntries()

The Object.fromEntries() function is currently not available in any version of Node.js. You need to npm install the object.fromentries polyfill.

The Object.fromEntries() function is intended to make it easy to convert a JavaScript Map into a JavaScript object:

Object .fromEntries( new Map ([[ 'hello' , 'world' ], [ 'foo' , 'bar' ]]));

A neat side effect is you can convert an array of key/value pairs into a JavaScript object:

Object .fromEntries([[ 'hello' , 'world' ], [ 'foo' , 'bar' ]]);

The primary rationale for this function is converting a map into an object, but the key/value pairs conversion is also useful.

For example, MongoDB doesn't allow storing keys with . . The way to store potentially dotted key names in MongoDB is with a key/value array. The Object.fromEntries() function along with its inverse Object.entries() make it easy to switch between objects and key/value arrays.

const packages = { 'lodash.get' : '4.x' , 'object.fromentries' : '2.x' }; await mongoose.model( 'Project' ).create({ packages: Object .entries(packages) }); await mongoose.model( 'Project' ).findOne().then(doc => { return Object .assign(doc, { packages: Object .fromEntries(doc.packages) }); });

Symbol#description

Symbols were introduced in ES2015 as a way of avoiding naming conflicts between properties. A symbol is a guaranteed unique property name:

const sym1 = Symbol ( 'foo' ); const sym2 = Symbol ( 'foo' ); const obj = { [sym1]: 'bar' , [sym2]: 'baz' }; console .log(obj[sym1]); console .log(obj[sym2]);

The first parameter to Symbol() is called the symbol's description. The description isn't an id, any number of symbols can have the same description without conflicts. A symbol's description is purely for debugging. The only exception is if you register the symbol in the global symbol registry using Symbol.for() .

Before ES2019, the only way you could access a symbol's description was using .toString() :

const sym = Symbol ( 'foo' ); sym.toString();

In Node.js 11 you can also access sym.description :

sym.description;

The description property is not writable. Setting sym.description is a no-op.

sym.description; sym.description = 'bar' ; sym.description;

Optional catch Binding

In Node.js 8 you always need to specify a variable in the catch clause of a try/catch , even if you never use the variable:

try { } catch (err) { }

ES2019's optional catch binding lets you skip defining a variable in catch . Optional catch binding is available in Node.js 10 and Chrome 66.

try { } catch { }

Moving On