For those who do not know, TC39 is the organization behind the standardization of the ECMAScript (JavaScript) specification. Ever since the major 2015 ES6 release, it has become the norm to release new features yearly.
For a feature to be added to a yearly release, it has to go through four proposal stages, with the final stage being approval. Let’s take a look at the five feature proposals that are currently in the final stage, with an anticipated release date for mid-2021.
The new logical assignment operators &&=
, ||=
, and ??=
are quite similar to the existing logical operators and are quite useful for assigning default values to variables.
||=
)x ||= y
The logical OR assignment operator is a short-circuit operation just like the logical OR operator (||
). The expression above is identical to x || (x = y)
, which means that y
will only be assigned to x
if x
is falsy. Otherwise, x
retains its original value.
Example:
const giveKey = () => { //perform randon computations return "somekey"; } let userDetails = {name:"chika", age:5, room:10, key:""} userDetails.key ||= giveKey() console.log(userDetails.key) //output : somekey
console.log(userDetails.key)
returns "somekey"
because the original key value was an empty string, which is a falsy value.
&&=
)x &&= y
The logical AND assignment operator is the opposite of the logical OR assignment operator. In this case, y
is only assigned to x
, if and only if x
is a truthy value. Otherwise, it retains its original value.
Example:
const deleteKey = () => { //perform randon computations return " "; } let userDetails = {name:"chika", age:5, room:10, key:"990000"} userDetails.key &&= deleteKey() console.log(userDetails.key) //output : ""
userDetails.key &&= deleteKey()
returns an empty string from the deleteKey
function because the previous value of userDetails
was a number, which is a truthy value.
??=
)x ??= y
The logical nullish operator only assigns y
to x
if x
is nullish (i.e., either null or undefined).
Example:
const getKey = () => { //perform randon computations return "somekey"; } let userDetails = {name:"chika", age:5, room:10,} userDetails.key ??= getKey() console.log(userDetails.key) //output : "somekey"
Here the output is "somekey"
because userDetails.key
does not exist in the response object (i.e., it is undefined).
String.replaceAll
const newString = oldString.replaceAll(pattern, replacement);
The replaceAll
method returns a new string in which all occurrences of a pattern
are replaced by a replacement
passed to it. The pattern
parameter can either be a string or a regex pattern, and the replacement
can either be a string or a function that creates a new string to replace the pattern
.
The replaceAll
method is a sequel to the String.replace
method, which only replaces the first occurrence of the pattern
with replacement
.
Example:
const str = "Linda is a self-taught developer.Linda will rule the world"; let newStr = str.replace("Linda","Micheal") //output: Micheal is a self-taught developer.Linda will rule the world let newStr = str.replaceAll("Linda","Micheal") //output: Micheal is a self-taught developer.Micheal will rule the world
The numeric separator simply improves the readability of large numbers by using the underscore (_
) character to separate number groups, just like you use commas to separate numbers in writing. Consider the number 1200044555
. At first glance, it’s quite difficult to decipher that this number is 1.2 billion and something.
Example:
const billGatesNetWorth = 1_200_044_555;
Now this is much more readable. Note that this doesn’t have any performance benefits or affect equality. 1_200_044_555
is still equal to 1200044555
.
Promise.any
Promise.any([promise1, promise2, promise3, ...]).then(....do something)
The Promise.any()
method is a new promise method that takes in a series of promises and resolves to the value of the first promise to successfully resolve. In other words, the Promise.any
resolves successfully if any of the promises resolve and rejects if all promises reject.
Example:
const promise1 = new Promise((resolve) => setTimeout((resolve) => resolve, 300, 'faster'); const promise2 = new Promise((reject) => setTimeout( (reject) =>reject, 100,"fastest") const promise3 = new Promise((resolve) => setTimeout( (resolve) => resolve,700,'fast'); const promises = [promise1, promise2, promise3]; Promise.any(promises).then((value)=>console.log(value)); //Output: faster
WeakRef
const weakRef = new WeakRef({ name:"Linda"; }); console.log(weakRef.deref().name) //output: Linda
WeakRef
is an advanced feature that should probably be avoided, according to the TC39 proposal notes. To understand what WeakRef
does, you need to first understand the concepts of object referencing and garbage collection in JavaScript.
const obj = {}
When you create an object in JavaScript and assign it to a variable, the JavaScript engine running on a browser allocates a memory address that stores the object. On the other hand, the variable to which the object is assigned stores the memory address of the object and not the value of the object itself. So, you can say that obj
holds a reference to the object assigned to it.
As objects are created and stored in memory, at some point, the browser may start to run out of memory and will need to free up memory space. Garbage collection is the process through which the browser engine frees up memory space by deleting objects that are no longer referenced by any variable.
WeakRef
creates a weak reference to the the object passed to it. This means that whenever the browser needs to run garbage collection, if the only reference to that object is from a WeakRef
variable, the JavaScript engine can safely remove the object from memory and free up space. This could be ideal for WebSocket data because of their short lifespans.
A WeakRef
is created with the new WeakRef
constructor, and the value of the WeakRef
variable can be accessed via the deRef
method.
The new ES2021 features are already supported by recent versions of major browsers like Chrome 85, Firefox 79, and Safari 14. However, to enable your code to run in older browsers, you need to set up your project with the Babel complier.
Install the following packages:
npm install --save-dev @babel/core @babel/cli @babel/preset-env npm install core-js
Create a babel.config.json
file at the root of your project:
{ "presets": [ [ "@babel/preset-env", { "useBuiltIns": "usage", "corejs": { "version": "3.8", "proposals": true } } ] ] }
The config above instructs Babel to use the env preset, which contains transforms for all the latest JavaScript features that have made it to stage four of the TC39 proposal process. It also instructs Babel to retrieve polyfills when needed from core JS.
Create a .browserlistrc
file at the root of your project to specify the target browsers for Babel to transform code in:
defaults maintained node versions
The defaults
query instructs Babel to transform and polyfill code only for:
maintained node versions
states that Babel should transform and polyfill code for all Node versions that are still maintained by the Node.js foundation.
Now, you can run:
./node_modules/.bin/babel src --out-dir lib
This will parse and transform all your JavaScript files in the src
directory into code suitable for older browsers (as specified by your .browserlistrc
file) and output each file to the lib
directory.
N.B., if you’re using a toolchain like Create React App or vue-cli, these configurations are already abstracted.
And that’s it. You’re good to go. Go and start using ES2021 today!
Debugging code is always a tedious task. But the more you understand your errors, the easier it is to fix them.
LogRocket allows you to understand these errors in new and unique ways. Our frontend monitoring solution tracks user engagement with your JavaScript frontends to give you the ability to see exactly what the user did that led to an error.
LogRocket records console logs, page load times, stack traces, slow network requests/responses with headers + bodies, browser metadata, and custom logs. Understanding the impact of your JavaScript code will never be easier!
Would you be interested in joining LogRocket's developer community?
Join LogRocket’s Content Advisory Board. You’ll help inform the type of content we create and get access to exclusive meetups, social accreditation, and swag.
Sign up nowBuild scalable admin dashboards with Filament and Laravel using Form Builder, Notifications, and Actions for clean, interactive panels.
Break down the parts of a URL and explore APIs for working with them in JavaScript, parsing them, building query strings, checking their validity, etc.
In this guide, explore lazy loading and error loading as two techniques for fetching data in React apps.
Deno is a popular JavaScript runtime, and it recently launched version 2.0 with several new features, bug fixes, and improvements […]
3 Replies to "New ES2021 features you may have missed"
Hi, thanks for writing this good article, I love it.
However I want to propose a correction for Promise.all in Promise.any part, The Promise.all should be reject if any of the promise rejected and resolve if all promise resolved.
https://developer.mozilla.org/en-
US/docs/Web/JavaScript/Reference/Global_Objects/Promise/all
Keep writing good stuff.
That was a typo. Should have been promise.any not promise.all. It will be corrected.
“`
const promise1 = new Promise((resolve) => setTimeout((resolve) => resolve, 300, ‘faster’);
const promise2 = new Promise((reject) => setTimeout( (reject) =>reject, 100,”fastest”)
const promise3 = new Promise((resolve) => setTimeout( (resolve) => resolve,700,’fast’);
“`
This promise code is just completely wrong, even if you fix the missing closing brackets. Your `setTimeout` calls take a `resolve => resolve` callback, but this reject is not the one from the promise, it’s an internal parameter of the callback. You might as well have passed the callback `foo => foo` , and it will have the same result.
`promise2` even renames the “resolve” parameter as `reject`. Further adding to the wrongness.
I believe you meant:
“`
const promise2 = new Promise((_, reject) => setTimeout(reject, 100,”fastest”));
“`