Categories
JavaScript

What’s New in JavaScript — ES2019

Spread the love

Ever since ES2015 released, which was a great leap forward in itself, JavaScript has been improving at a fast pace. Every year since, there have been new features added to the JavaScript specification. Features have been consistently added, like new syntax and new methods for built in JavaScript.

In ES2016 and 2017, the Object object has had methods like Object.values and Object.entries added. String methods like padStart and padEnd were added in ES2017. async and await , a shorthand syntax for chaining promises, were also added in ES2017. The includes methods for arrays were added in ES2016. ES2018 was another release with lots of new features. With ES2018, the spread syntax is now available for object literals. Rest parameters were also added. The for await...of loop, which is a loop syntax iterating through promises sequentially, was added. The SharedArrayBuffer object for representing raw binary data that cannot become detached was added. A finally function was also added to the Promise object.

In 2019, even more new JavaScript features have been added. 2019’s release brings more new methods to arrays and strings. The catch clause no longer needs to have a binding added to it — that is, the variable enclosed in parentheses after the catch keyword is longer required.

The description method has been added to the Symbol . The toString method of the Function object now preserves all characters of the function, so that it shows like it’s in your code, and now JSON.stringify will always encode in UTF-8.

Array.flat()

The Array.flat() function converts items in nested arrays to items in top level of the array. It does this recursively up to the given depth. To call the flat function on an array, we just have to path in the depth of the level that you want to flatten up to, which defaults to 1. It returns a new array with the sub-array elements concatenated into it. To flatten all levels of nested arrays, we can pass in Infinity .

For example, we can write:

const arr1 = [5, 6, [7, 8]];
console.log(arr1.flat());
// [5, 6, 7, 8]

const arr2 = [5, 6, [7, 8, [9, 10]]];
console.log(arr2.flat());
// [5, 6, 7, 8, [9, 10]]

const arr3 = [5, 6, [7, 8, [9, 10]]];
console.log(arr3.flat(2));
//  [5, 6, 7, 8, 9, 10]

const arr4 = [6, 7, [8, 9, [10, 11, [12, 13, [14, 15]]]]];
console.log(arr4.flat(Infinity));
//  [6, 7, 8, 9, 10, 11, 12, 13, 14, 15]

As you can see, this is a very handy method for removing nesting from a nested array. This is very valuable since it’s hard work to write our own function to recursively flatten nested arrays into a flattened array less nesting or without any nesting.

Empty slots in arrays are removed after Array.flat is ran. For example:

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

The empty slot is removed from the arr .

Array.flatMap()

The flatMap method maps an array’s entries into another array and then flatten the results. It’s equivalent to calling map on an array followed by flat with depth 1. It’s a great shorthand for mapping and then flattening which has some use cases since lots of arrays aren’t nested too deeply. The flatMap function take callback function on how to map the array. The callback function takes the current value of the array, index, and the originally array that the flatMap method is called on as parameters.

For example, we can use flatMap as in the following examples:

let arr = [1, 2, 3];

arr.map(x => [x * 10]);
// [[10], [20], [30]]]

arr.flatMap(x => [x * 10]);
// [10, 20, 30]

arr.flatMap(x => [[x * 2]]);
// [[2], [4], [6]]

As you can see, flatMap only flattens one level of the array. If we want to flatten more than one level after mapping we have to call map and flat separately.

Function.toString() Changes

Function objects always have the toString() method to get the string representation of a function. In ES2019, the toString() function now preserves comments and whitespaces to get the exact string representation of the function as we defined it.

For example, if we have the following:

function fn() {
  /* comment */
}

console.log(fn.toString())

We would now get the exactly the same thing as the code if we run toString() on the function. This means that this is logged:

function fn() {
  /* comment */
}

JSON.stringify() Fix

JSON.stringify now returns the correct characters for special unicode characters since now all characters are now UTF-8 encoded. The characters affected range from code U+D800 to U+DFF.

Now, if we call JSON.stringify on an object with those characters, we no longer get malformed characters back. If we call JSON.stringify then call JSON.parse on the string returned by JSON.parse , we get the same character back before we stringify it.

String.trimStart()

The string object now has a trimStart() function to trim the beginning whitespace of a string. There’s also a trimLeft() method which is an alias to this method.

For example, we can write:

let message = '   Hi! How's it going?   ';

console.log(message);

// We get '   Hi! How's it going?   '

let message = '   Hi! How's it going?   ';
console.log(message.trimStart());

// We get 'Hi! How's it going?   '

As we can see, the whitespace on the left side is gone. We can do the same thing with trimLeft() :

let message = '   Hi! How's it going?   ';
console.log(message.trimLeft());

// We get 'Hi! How's it going?   '

Note that a new string if returned with trimStart or trimLeft , so the original string stays intact. This prevents us from mutating the original string, which is handy for preventing mistakes from accidentally mutating objects.

String.trimEnd()

The trimEnd method removes whitespace from the right end of the string. trimRight is an alias of the trimEnd method. For example, we write:

let message = '   Hi! How's it going?   ';
console.log(message);
// We get '   Hi! How's it going?   '

let message = '   Hi! How's it going?';
console.log(message.trimEnd());
// We get '   Hi! How's it going?'

Note that a new string if returned with trimEnd or trimRight , so the original string stays intact. This prevents us from mutating the original string, which is handy for preventing mistakes from accidentally mutating objects.

Optional Catch Binding

With ES2019, the catch clause does not have to have a binding added to it. That is, the variable enclosed in parentheses after the catch keyword is longer required. This means that now we can write this:

try {
    ···
} catch {
    ···
}

Now we do not have to write this:

try {
    ···
} catch (error) {
    ···
}

This means that if we don’t have to use the error object, we don’t have to add the binding into the catch clause. It’s useful for ignoring the error, or if we don’t care what the error is. However, the error object is still handy for logging and checking for property inputs — and handling errors gracefully will prevent exceptions from being thrown.

For example, we can use it to catch any kind of exception, like with JSON.parse :

try {
  return JSON.parse(str);
} catch {
  return {}
}

We can handle errors with invalid JSON strings gracefully. The only issue with that is that we are just swallowing all exceptions, so it might be a better idea to catch some kinds of errors.

We can also use it to use browser features that aren’t supported in all browsers. For instance:

try {
  navigator.geolocation
} catch {
  return false;
}

Symbol.description

Symbols is a primitive data type that has its own type. There are some static properties and methods of its own that expose the global symbol registry. It’s like a built-in object, but it doesn’t have a constructor, so we can’t write new Symbol to construct a Symbol object with the new keyword. It’s mainly used for unique identifiers in an object. It’s a Symbol’s only purpose.

To create new symbols, we can write this:

const fooSymbol = Symbol('foo')

Note that each time we call the Symbol function, we get a new Symbol — this expression would be false:

Symbol('sym') === Symbol('sym')

With ES2019, we have a description property which is read only. It returns a string that has the parameter that we pass into the Symbol function or the object property path of well-known symbols.

If we use the example above and use the description property, we get this:

const fooSymbol = Symbol('foo');
console.log(fooSymbol.description);

We get foo logged.

With ES2019, we get more new features that we can use for developing JavaScript apps.

2019’s release brings more new methods to arrays and strings. The catch clause no longer has to have a binding added to it. That is, the variable enclosed in parentheses after the catch keyword is longer required.

The descrption method has been added to the Symbol .

The toString method of the Function object now preserves all characters of the function so that it shows like it’s in your code.

JSON.stringify will always encode in UTF-8, so now we don’t have malformed characters when we try to stringify characters ranging from code U+D800 to U+DFF.

Finally, arrays now can be flattened without writing our own code with the flat and flatMap methods.

By John Au-Yeung

Web developer specializing in React, Vue, and front end development.

Leave a Reply

Your email address will not be published. Required fields are marked *