What's new with JavaScript in 2020 - Ecmascript 2020/ES11

Person sharpening a tool

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.

 

Timeline Description automatically generated

 

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.

 

Graphical user interface, text, application

Description automatically generated

 

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.