What's new with JavaScript in 2020 - Ecmascript 2020/ES11
Background
Before ecmaScript came Javascript. The creator Brendan Eich set out to
create a language like, but simpler than Java. Javascript was originally
created for Netscape and before it went down, a project was started to
formalize the language and that became ecmascript. What we know today as
Javascript, is really vendor-specific implementations of ecmascript.
Ecmascript didn't really gain traction until version 6 and it has
continued to evolve since. Support for a given version is entirely
dependent on the environment such as node vs browser, which browser,
which version of that browser and such. Right now es version 13 also
known as es2022 is stable, BUT support for it in Node isn't stable until
version 17.9.1 (97% coverage). Since we are still on NodeJS 14,
ecmaScript support is limited currently to es11 or es2020. When we make
the move to Node 18.x, then we will have support for es version 13 aka
es2022.
Hopefully you have some idea of the versions and timelines now, but why
does it matter? Because each new ecmaScript version defines new
features. As vendors improve support for that new version, they are
exposed to developers in their products (like browsers and NodeJS). I
show you all these now to give you an idea how many new features have
released since es8/2017. I can't cover even a majority of them, but
today I'm going to briefly highly some that may prove helpful in
providing more stable code, code that's easier to read (and write tests
for *nod*) or help you avoid anti-patterns or just write simpler code.
Nullish coalescing
A bit like using OR to return the first/left-most non-null, non-empty
value; nullish coalescing returns the first/left-most non-null value,
even if it's empty.
1.
const response = {
2.
settings: {
3.
nullValue:
null
, height: 400, animationDuration: 0, headerText: '',
showSplashScreen:
false
4.
},
5.
};
6.
const undefinedValue = response.settings.undefinedValue ??
'some other default'
;
// result: 'some other default'
7.
const nullValue = response.settings.nullValue ??
'some other default'
;
// result: 'some other default'
8.
const headerText = response.settings.headerText ??
'Hello, world!'
;
// result: ''
9.
const animationDuration = response.settings.animationDuration ??
300;
// result: 0
10.
const showSplashScreen = response.settings.showSplashScreen ??
true
;
// result: false
11.
const x = '' || 'x';
// result: 'x'
12.
const x = '' ?? 'x';
// result: ''
Optional Chaining
When looking for a property value that's deep in a tree-like structure,
one often has to check whether intermediate nodes exist before you can
check for the deeper value. Optional chaining simplifies this by using a
question-mark before the dot-notation.
1.
const user = {};
2.
3.
Before:
4.
var
street = user.address.street;
// Error: cannot read properties of undefined var street =
user.address && user.address.street; // undefined
5.
Now:
6.
var
street = user?.address?.street;
// undefined
Logical assignment operator
This is a convenience operators, inspired by
Ruby's
. Javascript already has a dozen
mathematical assignment operators
, but we didn't have ones for the often used logical operators.
1.
// Ok, but could trigger setter.
2.
opts.foo = opts.foo ??
'bar'
3.
// No setter, but 'feels wrong' to write.
4.
opts.baz ?? (opts.baz =
'qux'
);
5.
// Setters are not needlessly called.
6.
opts.foo ??=
'bar'
7.
// No repetition of `opts.baz`.
8.
opts.baz ??=
'qux'
;
|
9.
// This always logs "setter called"
10.
obj.x += 1;
11.
assert.equal(obj.x, 1);
12.
// Logical operators do not call setters unnecessarily
13.
// This will not log.
14.
obj.x ||= 2;
15.
assert.equal(obj.x, 1);
16.
// But setters are called if the operator does not short
circuit
17.
// "setter called"
18.
obj.x &&= 3;
19.
assert.equal(obj.x, 3);
|
Object rest/spread
ECMAScript 6 introduces
rest elements
for ARRAY destructuring assignment and
spread elements
for ARRAY literals. With es11, we get
rest properties
for OBJECT destructuring assignment and
spread properties
for OBJECT literals.
1.
let
{ x, y, ...z } = { x: 1, y: 2, a: 3, b: 4 };
2.
x;
// 1
3.
y;
// 2
4.
z;
// { a: 3, b: 4 }
5.
let
n = { x, y, ...z };
6.
n;
// { x: 1, y: 2, a: 3, b: 4 }
Promise.allsettled
Previously we were given Promise.all, Promise.race, and Promise.any.
Other Promise combinators can short-circuit, discarding the results of
input values that lose the race to reach a certain
state. Promise.allSettled is unique in always waiting for all
of its input values. Promise.allSettled returns a promise that is
fulfilled with an array of promise state snapshots, but only after all
the original promises have settled, i.e. become either fulfilled or
rejected.
'The Promise.allSettled() method returns a promise that fulfills after
all of the given promises have either fulfilled or rejected, with an
array of objects that each describes the outcome of each promise.'
1.
const promise1 = Promise.resolve(3);
2.
const promise2 =
new
Promise((resolve, reject) => setTimeout(reject, 100,
'foo'
));
3.
const promises = [promise1, promise2];
4.
Promise.allSettled(promises).
5.
then((results) => results.forEach((result) =>
console.log(result.status)));
6.
// expected output:
7.
// "fulfilled"
8.
// "rejected"
Conclusion
ECMAScript is constantly evolving and the more current your environment (latest Node.js, browser, or other client), the more features you'll have access to. Be sure to keep an eye on which version of eslint you want to target by watching resources like https://node.green/ and https://caniuse.com/?search=es11.