First of all let me apologise for not writing as frequent as I wouldβve liked. Itβs been a crazy busy couple of weeks and I had heaps of fun speaking at DDD Perth 2019.
That taken care of, this time I thought letβs go through the new features which are added into the ECMAScript 2019 (aka ES2019 or ES10), because theyβre super exciting and make our lives much easier π.
At a glance, this version adds a few built-in functions on Array.prototype
, flat
and flatMap
. Then we have Object.fromEntries
for directly turning the return value of Object.entries
into a new Object.
We also have trimStart
and trimEnd
on String.prototype
over the widely used non-standard versions String.prototype.trimLeft
and trimRight
.
Another exciting feature is optional catch
binding parameters. In addition to those, there are some JSON improvements, addition of Symbol.prototype.description
which allows you to specify a description for your symbol, JSON.stringify
returns well-formed UTF-8 regardless of input, and at last clarifying Function.prototype.toString
by requiring that it either return the corresponding original source text or a standard placeholder.
So if youβre ready letβs dig in.
Array.prototype.{flat, flatMap}
flat()
is a new method which letβs you create a one-dimensional array from a multi-dimensional one.
Imagine we have an array like below:
const myArray = [1, 2, 3, [4, 5, 6, [7, 8, 9, [10, 11, 12]]]];
Prior to flat
if you wanted to achieve this, you had to do something like this:
const myNewArray = [].concat.apply([], myArray)
// [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
Or:
var myNewArray = myArray.reduce(
function(prev,curr) {
return prev.concat(curr)
}
)
// [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
With this new addition, it would be as simple as:
var myNewArray = myArray.flat(4);
// [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
You can also chain multiple calls:
var myNewArray = myArray.flat().flat().flat().flat();
// [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
The argument into the flat
function just specifies how deep it should look into the array. If youβre not sure how deep the array is, simply use Infinity
as input:
var myNewArray = myArray.flat(Infinity);
// [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
And if you donβt provide any input, by default it only goes one level deep:
var myNewArray = myArray.flat();
// [1, 2, 3, 4, 5, 6, Array(4)];
flatMap
on the other hand, allows you to map each element using a mapping function and then flattens the result into a new array. Think of it as chaining a map
function with a single flat
. However, it can be really helpful both in terms of usage and efficiency of execution.
let myArray = [1, 2, 3, 4, 5];
let mappedArray = myArray.map(x => [x, x * 2]);
// [Array(2), Array(2), Array(2), Array(2), Array(2)]
// 0: (2)[1, 2]
// 1: (2)[2, 4]
// 2: (2)[3, 6]
// 3: (2)[4, 8]
// 4: (2)[5, 10]
let mappedFlattenedArr = mappedArray.flat();
// [1, 2, 2, 4, 3, 6, 4, 8, 5, 10]
let myNewArray = myArray.flatMap(v => [v, v * 2]);
// [1, 2, 2, 4, 3, 6, 4, 8, 5, 10]
String.prototype.{trimStart, .trimEnd}
These methods are fairly obvious as to what they will do for us. Just keep in mind that we had trimLeft
which will be replaced by trimStart
and trimRight
which will be replaced by trimEnd
.
let message = ' This is a string with white space around ';
message = message.trimStart();
// 'This is a string with white space around '
message = message.trimEnd();
// 'This is a string with white space around'
Object.fromEntries
This method get an Iterable
and transforms key-value pairs to an object. But letβs see what is an Iterable
:
JavaScript supports a protocol by which objects such as arrays can be used by control structures such as
for
β¦of
and the spread operator...
to loop through data sequentially. This is referred to as the iterable and the data structures that support this functionality are called iterables. While JavaScript provides maps, arrays and sets with an iterable property from the get-go, plain objects do not have this by default.
To see this in action:
let entries = new Map([["name", "john"], ["age", 22]]);
let newObj = Object.fromEntries(entries);
// { name: 'john', age: 22 }
A real life use case is when parsing query strings:
let query = Object.fromEntries(new URLSearchParams('foo=bar&baz=qux'));
// { foo: 'bar', baz: 'qux' }
Optional catch binding allows us to use try/catch
without the error
parameter inside the catch block.
Previously you had to use this syntax regardless of whether you cared about err
or not, such as when you had to fall back to feature to support older browsers:
try {
// try to use a web feature which may not be implemented
} catch (unused) {
// fall back to a less desirable web feature with broader support
}
With ES2019
you can do:
try {
// ...
} catch {
// ...
}
Symbol.description
This new read-only description property is a string returning the optional description of Symbol
objects. This method is encouraged to be used instead of Symbol.prototype.toString
where it wasnβt obvious what will be returned.
let description = 'This symbol represents an emoji π';
let mySym = Symbol(description);
// Symbol('This symbol represents an emoji π')
console.log(mySym.description);
'This symbol represents an emoji π'
Function.toString
This method is a really useful one which returns the source code of a function. Imagine doing a troubleshooting on a block of code which is using a third party function. This can potentially help you to see the implementation (given itβs got source maps).
function myFn(emoji) {
let msg = `${emoji} is hellav an emoji`;
console.log(msg);
}
console.log(myFn.toString());
// "function myFn(emoji) {
// let msg = `${emoji} is hellav an emoji`;
// console.log(msg);
// }"
Of course this doesnβt work for everything. If we try it for map
function on array:
Array.prototype.map.toString();
// "function map() { [native code] }"
Since the implementation is not written in JavaScript, it will just show you that this function is written in native code.
JSON.stringify
The team have done an improvement with Unicode characters and now this method canβt return malformed data.
// Non-BMP characters still serialize to surrogate pairs.
JSON.stringify('π')
// β '"π"'
JSON.stringify('\uD834\uDF06')
// β '"π"'
// Unpaired surrogate code units will serialize to escape sequences.
JSON.stringify('\uDF06\uD834')
// β '"\\udf06\\ud834"'
JSON.stringify('\uDEAD')
// β '"\\udead"'
Array.sort
StabilityThe team has decided to change the sort implementation so that it would be stable (that is, elements that compare equal must remain in their original order).
const grades = [
{ topic: 'math', grade: 10 },
{ topic: 'literacy', grade: 10 },
{ topic: 'chemical', grade: 13 },
{ topic: 'geography', grade: 12 },
{ topic: 'modern history', grade: 12 },
{ topic: 'art', grade: 13 },
{ topic: 'computer basics', grade: 14 },
{ topic: 'algebra', grade: 14 },
];
grades.sort(a, b => a.grade - b.grade);
// 0: {topic: "math", grade: 10}
// 1: {topic: "literacy", grade: 10}
// 2: {topic: "geography", grade: 12}
// 3: {topic: "modern history", grade: 12}
// 4: {topic: "chemical", grade: 13}
// 5: {topic: "art", grade: 13}
// 6: {topic: "computer basics", grade: 14}
// 7: {topic: "algebra", grade: 14}
In general JavaScript is moving in the right direction for helping developers write more stable, reliable and consistent code. You can find more information on their GitHub repo here.
Hope to see more awesome features in JavaScript and see you soon with another article.