Javascript new features that introduced in ECMAScript 2020
Tags: javascript, codenewbie, tutorial, beginners
Published: 2023-01-20 22:21:34

Here are some of the new features introduced in ECMAScript 2020:

##Optional chaining operator (?.):

Consider the following example.
```javascript
const person = {
   name: 'haziq',
   city: 'Lahore'
};

const name = person ? person.name : undefined;
```
The code checking if the variable `person` is defined and has a `property name`. If `person` is defined and has a `property name`, it will assign the value of `person.name` to the variable `name`. If `person` is not defined or doesn't have a `property name`, it will assign the string `'no name'` to the variable `name`.

But! with the help of optional chaining you'll have more compact and readable code, as shown:
```javascript
const person = {
   name: 'haziq',
   city: 'Lahore'
};

const name = person?.name
```
The code is using the `Optional chaining operator` ?. to access the property `name` of the object `person` safely. It is checking if the object `person` has property `name` if it does, it will assingn the value to variable `name`, if it doesn't have it will return `undefined`.

##Nullish coalescing operator (??):
Nullish coalescing operator allows you to provide a default value when a given value is `null` or `undefined`. It is similar to the logical `OR` operator (||), but it only returns the right-hand side operand when the left-hand side operand is `null` or `undefined`.

Here is an example of how to use the nullish coalescing operator:

```javascript
const user = { name: "John" };
console.log(user.age ?? 18); // 18
```
In this example, the variable `user` is an `object` with a property `name` and no property age. The nullish coalescing operator (??) is used to check if the value of `user.age` is `null` or `undefined`. Since `user.age` is `undefined`, the right-hand side operand 18 is returned.


##Dynamic imports:
Dynamic imports allows you to load a module on demand at runtime. It allows you to import a module as a function, and you can call that function to load the module.

Here is an example of how to use dynamic imports:

```javascript
async function loadModule() {
  const module = await import('./module.js');
  console.log(module.default);
}
loadModule();
```
In this example, `loadModule()` is an async function that uses the `await` keyword to wait for the module to be loaded before accessing it. The `import()` function is called with the path to the module as an argument. It returns a promise that resolves with the exports of the module.

The `module.default` is used to access the default export of the module.

Dynamic imports are particularly useful in situations where you only want to load a module when it's needed, rather than loading all the modules at the beginning of the application. This can improve the performance of your application by reducing the initial load time.

It's also useful for code splitting, that is, separating the application into smaller chunks that can be loaded on demand. This can reduce the amount of JavaScript that needs to be loaded and parsed on initial load, making the application faster to start and use.

##bigInt:
`bigint` is a new primitive type that can represent integers with arbitrary precision, unlike the regular Number type, which is limited to a `53-bit` integer range. The syntax for creating a bigint is to add the "n" suffix to the end of the number. 
Here is an example of creating and using a bigint in JavaScript:
```javascript
let bigInt = 9007199254740992n;
console.log(bigInt); // 9007199254740992n
console.log(typeof bigInt); // bigint

let sum = bigInt + 1n;
console.log(sum); // 9007199254740993n

let difference = bigInt - 1n;
console.log(difference); // 9007199254740991n
```
You can also use the `BigInt()` function to convert a `number` or `string` to a `bigint`. This is useful when you're working with variables that may or may not contain bigint values:
```javascript
let num = 9007199254740992;
let bigIntNum = BigInt(num);

console.log(bigIntNum); // 9007199254740992n
console.log(typeof bigIntNum); // bigint
```

##import meta data:
The `import.meta` object provides access to metadata associated with the current module. This metadata can include information about the file path, URL, and more.

The `import.meta` object is only available inside a module and is not available in scripts.

```javascript
import.meta.url // 'file:///path/to/module.js'
```

Another example, you can use import.meta to access the directory of the current module:
```javascript
import.meta.dir // '/path/to/'
```

You can also use import.meta to access the filename of the current module:
```javascript
import.meta.filename // '/path/to/module.js'
```

You can also use import.meta in dynamic import statement
```javascript
import(import.meta.url.replace('.js', '-dynamic.js'))
```
_It's important to note that import.meta is a relatively new feature and is not yet widely supported in all JavaScript environments. It is currently supported in Node.js and modern web browsers (Chrome, Firefox, and Safari)._

##New export syntax:
New export syntax allows for more flexibility in how you structure and organize your code by giving you more options for exporting and importing values.

Here are a few examples of the new export syntax:

Named exports: You can use the `export` keyword to export a value by its name. For example:
```javascript
export const name = 'John Doe';
```

Default exports: You can use the `export default` statement to export a default value from a module. For example:
```javascript
export default function add(a, b) {
    return a + b;
}
```

Re-exporting: You can use the export statement to re-export a value from another module. For example:
```javascript
export { name } from './module.js';
```
Renaming imports and exports: You can use the `as` keyword to give a different name to an imported or exported value.
```javascript
export { name as myName } from './module.js';
```
_This new export syntax provides more flexibility in structuring and organizing your code by giving you more options for exporting and importing values._

##matchAll():
The `matchAll()` method is a string method that returns an iterator of all results matching a regular expression in a given string. It's similar to the `match()` method, but `matchAll()` returns all matches, whereas `match()` returns only the first match.

Here's an example of using the `matchAll()` method to find all occurrences of a word in a string:
```javascript
let str = "The quick brown fox jumps over the lazy dog.";
let regex = /\bthe\b/gi;
let matches = str.matchAll(regex);

for (let match of matches) {
    console.log(match[0]);
}
// Output: "The" "the"
```
In the above example, `matchAll()` method is used to find all occurrences of the word "the" in the string "The quick brown fox jumps over the lazy dog.". The `for...of` loop is used to iterate through the matches and print each one.

##globalThis:
The `globalThis` object refers to the global object of the current environment, whether it be a web browser or a Node.js runtime. It provides a consistent way to access the global object regardless of the environment.

In a web browser, the `globalThis` object refers to the window object, which is the global object for client-side JavaScript. For example:
```javascript
console.log(globalThis === window); // true
```
It provides a consistent way to access the global object across different environments, and it's useful in cases where you don't know the environment in which your code will be running.

##Promise.allSettled():
The `Promise.allSettled()` method is used to wait for an array of promises to settle (either resolve or reject). It returns a promise that is fulfilled with an array of objects that each describe the outcome of each promise.

Here's an example of using `Promise.allSettled()` to wait for an array of promises to settle:
```javascript
let promise1 = new Promise((resolve, reject) => {
    setTimeout(() => {
        resolve("Promise 1 resolved");
    }, 2000);
});
let promise2 = new Promise((resolve, reject) => {
    setTimeout(() => {
        reject(new Error("Promise 2 rejected"));
    }, 1000);
});
let promise3 = new Promise((resolve, reject) => {
    setTimeout(() => {
        resolve("Promise 3 resolved");
    }, 3000);
});
let promises = [promise1, promise2, promise3];

Promise.allSettled(promises).then(results => {
    results.forEach(result => {
        if (result.status === "fulfilled") {
            console.log(`Promise fulfilled: ${result.value}`);
        } else {
            console.log(`Promise rejected: ${result.reason}`);
        }
    });
});
```
In the above example, `Promise.allSettled()` is used to wait for an array of promises to settle. The `then()` method is used to handle the settled results. The `forEach()` loop is used to iterate through the results and check the status of each promise.

It's worth noting that `Promise.allSettled()` method is similar to `Promise.all()` but `Promise.allSettled()` waits for all promises to settle, regardless of whether they resolve or reject. `Promise.all()` method waits for all promises to resolve and if any promise is rejected it will cause the whole `Promise.all()` to reject.

_It's also worth noting that features that are not supported in older environments will not throw any error but they will not work as expected and you have to check the browser support before using these features._