Skip to main content

9 posts tagged with "ES2019"

View All Tags

Subsume JSON a.k.a. JSON ⊂ ECMAScript

· 6 min read
Mathias Bynens ([@mathias](https://twitter.com/mathias))

With the JSON ⊂ ECMAScript proposal, JSON becomes a syntactic subset of ECMAScript. If you’re surprised that this wasn’t already the case, you’re not alone!

The old ES2018 behavior

In ES2018, ECMAScript string literals couldn’t contain unescaped U+2028 LINE SEPARATOR and U+2029 PARAGRAPH SEPARATOR characters, because they are considered to be line terminators even in that context:

// A string containing a raw U+2028 character.
const LS = '
';
// → ES2018: SyntaxError

// A string containing a raw U+2029 character, produced by `eval`:
const PS = eval('"\u2029"');
// → ES2018: SyntaxError

This is problematic because JSON strings can contain these characters. As a result, developers had to implement specialized post-processing logic when embedding valid JSON into ECMAScript programs to handle these characters. Without such logic, the code would have subtle bugs, or even security issues!

Stable `Array.prototype.sort`

· 3 min read
Mathias Bynens ([@mathias](https://twitter.com/mathias))

Let’s say you have an array of dogs, where each dog has a name and a rating. (If this sounds like a weird example, you should know that there’s a Twitter account that specializes in exactly this… Don’t ask!)

// Note how the array is pre-sorted alphabetically by `name`.
const doggos = [
{ name: 'Abby', rating: 12 },
{ name: 'Bandit', rating: 13 },
{ name: 'Choco', rating: 14 },
{ name: 'Daisy', rating: 12 },
{ name: 'Elmo', rating: 12 },
{ name: 'Falco', rating: 13 },
{ name: 'Ghost', rating: 14 },
];
// Sort the dogs by `rating` in descending order.
// (This updates `doggos` in place.)
doggos.sort((a, b) => b.rating - a.rating);

`Symbol.prototype.description`

· One min read
Mathias Bynens ([@mathias](https://twitter.com/mathias))

JavaScript Symbols can be given a description upon creation:

const symbol = Symbol('foo');
// ^^^^^

Previously, the only way to access this description programmatically was indirectly through Symbol.prototype.toString():

const symbol = Symbol('foo');
// ^^^^^
symbol.toString();
// → 'Symbol(foo)'
// ^^^
symbol.toString().slice(7, -1); // 🤔
// → 'foo'

However, the code is slightly magical-looking, not very self-explanatory, and violates the “express intent, not implementation” principle. The above technique also doesn’t let you distinguish between a symbol with no description (i.e. Symbol()) and a symbol with the empty string as its description (i.e. Symbol('')).

`Object.fromEntries`

· 4 min read
Mathias Bynens ([@mathias](https://twitter.com/mathias)), JavaScript whisperer

Object.fromEntries is a useful addition to the built-in JavaScript library. Before explaining what it does, it helps to understand the pre-existing Object.entries API.

Object.entries

The Object.entries API has been around for a while.

For each key-value pair in an object, Object.entries gives you an array where the first element is the key, and the second element is the value.

Object.entries is especially useful in combination with for-of, as it enables you to very elegantly iterate over all key-value pairs in an object:

const object = { x: 42, y: 50 };
const entries = Object.entries(object);
// → [['x', 42], ['y', 50]]

for (const [key, value] of entries) {
console.log(`The value of ${key} is ${value}.`);
}
// Logs:
// The value of x is 42.
// The value of y is 50.

Unfortunately, there’s no easy way to go from the entries result back to an equivalent object… until now!

Object.fromEntries

The new Object.fromEntries API performs the inverse of Object.entries. This makes it easy to reconstruct an object based on its entries:

const object = { x: 42, y: 50 };
const entries = Object.entries(object);
// → [['x', 42], ['y', 50]]

const result = Object.fromEntries(entries);
// → { x: 42, y: 50 }

One common use case is transforming objects. You can now do this by iterating over its entries, and then using array methods you might already be familiar with:

const object = { x: 42, y: 50, abc: 9001 };
const result = Object.fromEntries(
Object.entries(object)
.filter(([ key, value ]) => key.length === 1)
.map(([ key, value ]) => [ key, value * 2 ])
);
// → { x: 84, y: 100 }

In this example, we’re filtering the object to only get keys of length 1, that is, only the keys x and y, but not the key abc. We then map over the remaining entries and return an updated key-value pair for each. In this example, we double each value by multiplying it by 2. The end result is a new object, with only properties x and y, and the new values.

`Array.prototype.flat` and `Array.prototype.flatMap`

· 2 min read
Mathias Bynens ([@mathias](https://twitter.com/mathias))

Array.prototype.flat

The array in this example is several levels deep: it contains an array which in turn contains another array.

const array = [1, [2, [3]]];
// ^^^^^^^^^^^^^ outer array
// ^^^^^^^^ inner array
// ^^^ innermost array

Array#flat returns a flattened version of a given array.

array.flat();
// → [1, 2, [3]]

// …is equivalent to:
array.flat(1);
// → [1, 2, [3]]

Well-formed `JSON.stringify`

· One min read
Mathias Bynens ([@mathias](https://twitter.com/mathias))

JSON.stringify was previously specified to return ill-formed Unicode strings if the input contains any lone surrogates:

JSON.stringify('\uD800');
// → '"�"'

The “well-formed JSON.stringify” proposal changes JSON.stringify so it outputs escape sequences for lone surrogates, making its output valid Unicode (and representable in UTF-8):

Optional `catch` binding

· One min read
Mathias Bynens ([@mathias](https://twitter.com/mathias))

The catch clause of try statements used to require a binding:

try {
doSomethingThatMightThrow();
} catch (exception) {
// ^^^^^^^^^
// We must name the binding, even if we don’t use it!
handleException();
}

In ES2019, catch can now be used without a binding. This is useful if you don’t have a need for the exception object in the code that handles the exception.

try {
doSomethingThatMightThrow();
} catch { // → No binding!
handleException();
}

Optional catch binding support

`String.prototype.trimStart` and `String.prototype.trimEnd`

· One min read
Mathias Bynens ([@mathias](https://twitter.com/mathias))

ES2019 introduces String.prototype.trimStart() and String.prototype.trimEnd():

const string = '  hello world  ';
string.trimStart();
// → 'hello world '
string.trimEnd();
// → ' hello world'
string.trim(); // ES5
// → 'hello world'

This functionality was previously available through the non-standard trimLeft() and trimRight() methods, which remain as aliases of the new methods for backward compatibility.

const string = '  hello world  ';
string.trimStart();
// → 'hello world '
string.trimLeft();
// → 'hello world '
string.trimEnd();
// → ' hello world'
string.trimRight();
// → ' hello world'
string.trim(); // ES5
// → 'hello world'