ES stands for ECMAScript and that again stands for European Computer Manufacturers Association (ECMA) Script, which is nothing more but a standard that ensures the interoperability of webpages across different browsers. This standard is imposed by the TC39, an international JavaScript community that is motivated to maintain and evolve the definition of JavaScript.
So, what's new you ask, well there a few things that the new standard improves within the JS and how it can be written better. Here are few things which are new in ES2021:
Let us take a look at each one of them in detail one by one and also see how we can use these in our day to day practical programming scenerios. You can also follow along some of the examples below in your own browser's console or any other handy code editor.
Let us firstly start off with the new logical assignment operators, but first let know what the basic definition of operator is in this context, an operator is capable of manipulating a certain value or operand. You might have already come across some of them in you day to day programming problems, take the ternary operator for example.
You must have already heard of the logical operators in JS and probably used them a fair bit in your programming, logical operators are used to determine the logic between variables or values. JS has && (and) || (or) ! (not) as its well known logical operators. Coming to the new ES2021 JS has released three logical assignment operators which by the sound of it feels like it performs a logical operation followed by an assignment, and to be fair, that is what quite happens. Let us take a look at new operators, namely.
||=&&=??=||= )In simplest of words, the logical OR assignment operator ||= accepts two operands and assigns the right operand to the left operand if the left operand is falsy. Take a look at the code below
//"Or Or Equals"
x ||= y
//Equivalent to : x || (x = y), only assigns if x is Falsy
Now you must understand what falsy means in JavaSript, the shortest definition I could come up with is from MDN, that states, A falsy value is a value that is considered false when encountered in a Boolean context. For example falsy could be 0, empty string (""), undefined, null, NaN etc. JavaScript uses type conversion to convert any value to a Boolean in contexts that require it, such as conditionals or loops.
Now the understanding of logical OR assignment operator becomes more clearer, so, when the left operand is falsy, then in that case this operator assigns the value of the right operand to the left.
In other words, we can also say that when the left hand side of the operation does not exists (or is falsy), then the value on the right hand side gets assigned to the left. When it is not falsy (or exists) then in that scenerio it leaves it as is, without assigning anything. So, in a day-to-day programming scenerio, let us take the simple login mechanism in which we need to set the authToken value to a variable.
let authToken = '123456789abcde';
let incomingAuthToken = '987654321edcba';
//Using logical OR assignment operator to override the token only when its inital value is falsy
authToken ||= incomingAuthToken;
console.log(authToken); //Outputs: '123456789abcde' as it does not change if the value is not falsyAs you can see from the code above that the left operand i.e. authToken does not get the new value assigned to it, reason being, it already had a truthy value. Now let us see what if it had a falsy value instead what would have happened.
let authToken = ''; //empty strings are considered as falsy in JS
let incomingAuthToken = '987654321edcba';
//Using logical OR assignment operator this time overrides the value as the intial value
//is a falsy
authToken ||= incomingAuthToken;
console.log(authToken); //Outputs: '987654321edcba', since the authToken had a falsy valueAs expected we see the assignment occur this time, due to the value of the left operand being falsy. So in even simpler words, if a variable on the left has a value that is falsy then assign the value of the right to the left variable else, if it has a truthy value, then keep the old value without manipulating it. Let us take a look at the && variant of this logical assignment operator.
&&= )The logical AND assignment operator &&= is just the opposite of the logical OR assignment. In this case, the right operand is assigned to the left one only if the left operand is a truthy value. Otherwise, it retains its original value.
Let us see a live usage example
let adminObj = {
name: 'Shreyas',
title: 'System Administrator',
role: 'admin',
id: '12312esafd21343XSDasw',
profile_complete: true,
};
//I want to check if the admin has the role of truthy and then only run a particular function
const displayRole = () => {
console.log('Role attribute exists: ', adminObj[role]);
};
//Now i want to run this function only if role attribute exists or is a truthy, then
adminObj[role] &&= displayRole();
//Outputs: Role attribute exists: 'admin'These operators can come in handy in some scenerios
//Using a Logical Assignment Operator
var x = true
var y = false
// Before ES2021
if (!x) {
x = y
}
// Same logic using the new logical OR assignment operator
x ||= y // returns x
// Before ES2021
if (x) {
x = y
}
// Same logic using the new logical AND assignment operator
x &&= y // returns y
The word nullish in the MDN docs is defined as a value in JavaScript, which is either null or undefined and by nature nullish values are falsy. So, the logical nullish operator ( ??= ) only assigns the left operand to the right if the right operand is nullish (i.e. null or undefined).
Usage example
let adminObj = {
name: 'Shreyas',
title: 'System Administrator',
role: 'admin',
id: '12312esafd21343XSDasw',
profile_complete: true,
};
//I want to check if the adminObj has the fingerprintKey entry,
//if not I want to assign it a admin finger print default value
const initializeFingerprint = () => {
const defaultFingerprint = new Fingerprint('admin') //evaluates to a unique id key
return defaultFingerprint;
};
//Now i want to run this function and append its return value
//only if the fingerprintKey value on the object is nullish
adminObj[fingerprintKey] &&= initializeFingerprint();
console.log(adminObj[fingerprintKey])
//Outputs: '87t5gieuh4wto58gluh745t8hieou74t58wo' //Object now has the fingerprint key initializedThe numeric seperator could be thought of as a QOL (quality of life) improvement to JavaScript, it doesn't do much but it does improve the readability of large numbers by using ( _ )
character to seperate number groups, similar to how we use commas to seperate numbers in writing. Consider an example: 290300000000, when written like that at first glance it is quite difficult to decipher that number but when the same number is written as 290,300,000,000 or using the new numeric operator as 290_300_000_000, it suddenly becomes more clearer to grasp that it resembles 290,00 Million, which also happens to be Elon Musk's net worth.
This actually comes in clutch when building an application that has a lot of numbers like price, MRP, numeric values etc. associated with it. Take a look below for example.
//Before we could only write number as follows
const graphicsCardPrice = 1000000 //This is NOT so readable
//But using the new numeric seprators we could write
const graphicsCardPriceUsingNumericSeperator = 1_000_000
// The above is more readable and on first look at it you know it is a million
//Keep in mind both variables are equal though
graphicsCardPrice === graphicsCardPriceUsingNumericSeperator //Both are equal
//Outputs: true
As you can see graphicsCardPriceUsingNumericSeperator is much more readable compared to the graphicsCardPrice. Note that this does not have any performance improvements or benefits, it is just eye candy for the developers, nor does this affect equality as you can see in the code above
The new replaceAll method is a sequel to the String.replace method, String.replace only replaces the first occurrence of the pattern with replacement. Whereas, the new replaceAll replaces all occurrences of the pattern.
const newString = oldString.replaceAll(pattern, replacement);A simple usage example that outlines the differences between both replace methods.
//Let us have a default paragraph
let paragraph = 'Jeff is the richest man on the planet right now, Jeff has also invested in space technology which has made him the richest in the business, Jeff owns a lot of cars and real estates. Jeff will soon own half of the islands in the world.'
//I want to replace the word Jeff with Elon in the above paragraph
let modifiedParagraph = paragraph.replace('Jeff', 'Elon')
//Outputs: 'Elon is the richest man on the planet right now, Jeff has also invested in space technology which has made him the richest in the business, Jeff owns a lot of cars and real estates. Jeff will soon own half of the islands in the world.'
let modifiedParagraphUsingReplaceAll = paragraph.replaceAll('Jeff', 'Elon')
//Outputs: 'Elon is the richest man on the planet right now, Elon has also invested in space technology which has made him the richest in the business, Elon owns a lot of cars and real estates. Elon will soon own half of the islands in the world.'
You can see that modifiedParagraphUsingReplaceAll replaces all instances of the pattern within a string.
If you already don't have clarity on promises, then I definately recommend to check out Dmitri's blog, this would serve you as an excellent reference whenever you get confused about promises in JavaScript.
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.
Some people might confuse this with promise.race(). The Promise.any() resolves with the first promise to fulfil, even if a promise rejects first. This is in contrast to Promise.race(), which resolves or rejects with the first promise to settle. If no promises in the iterable fulfill, the Promise.any() rejects with an AggregateError that groups individual errors. The AggregateError is a subclass of Error.
For clear differences between Promise.race() and Promise.any. Visit this link
Checkout this example from MDN docs to see how we can harness this is a lazy/selective load app environment.
Javascript utilizes garbage collection (GC) for automatic memory management. The purpose of a garbage collector is to monitor memory allocation and determine when a block of allocated memory is no longer needed and reclaim it. The object is not collected, by the garbage collector as long as a reference to that object exists. This keeps the object in memory, leaving less memory for usage. To tackle this very problem, ES2021 has added WeakRef and FinalizationRegistry features to handle garbage collection in more apt manner. JavaScript does a lot of work in the background to keep things running smoothly on the front.
Let us checkout both of these fancy terms in detail and how they contribute towards assisting JavaScript in doing its background tasks more effeciently.
WeakRef is the new enhancement in the world of objects in Javascript. As the name suggests, WeakRef contains the weak reference to the Javascript object. If any object contains the weakref reference then the JS garbage collector clears the object and reclaims the memory. For a detailed overview on weakref checkout: WeakRef TC39 Proposal.
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
A FinalizationRegistry object lets you request a callback when an object is garbage-collected. FinalizationRegistry provides a way to request that a cleanup callback get called at some point when an object registered with the registry has been reclaimed (garbage-collected). (Cleanup callbacks are sometimes called finalizers.)
Note: Cleanup callbacks should not be used for essential program logic.
Both of these additions are well and good for the internals of JavaScript. The proposal recommends you avoid these wherever possible as they are still in an inital stage of implementation and with time their application is supposed to improve even further.
And on that note, let us end this escapade here. 😄 I hope you learnt something new in this read. JavaScript will continue to evolve and improve over the coming years, and there are a lot of more amazing features that are yet to come in the latest proposal. These new features, apart from the weakRef and finalizationRegistryObjects are quite useful, hope some of my examples may have persued you to try and adapt to the latest conventions and helped you better your codebase.
I hope you will use these new exciting features in your daily programming problems and have a great time implementing your code.
I will be publishing more posts related to React, Flutter & Docker. So stay tuned. ✋