New JavaScript Features Coming in ES2020 That You Can Use Now (Part 2)

Since 2015, the JavaScript is evolving fast with lots of new features coming out in each iteration. New versions of the JavaScript language specification have been updated yearly, with new language feature proposals being finalized faster than ever.

This means that new features are getting incorporated into modern browsers and other JavaScript run-time engines like Node.js at a pace that we haven’t seen before. In 2019, there are many new features that are in the ‘Stage 3’ phase, which means that it’s very close to being finalized and browsers are getting support for these features now.

If we want to use them for production code, we can use something like Babel to transpile them to older versions of JavaScript so they can be used in older browsers like Internet Explorer if needed.

In this article, we’ll look at static fields and methods in classes and using the await keyword at the top level in regular code and module exports.

Static Fields and Methods in Classes

Static fields in classes is a new feature that’s coming soon to browsers and Node.js. It lets us add static fields for classes that do not need an instance of the class to be created to be accessed. They can both be private or public. It’s a handy replacement for enums. For example, with the latest proposal, we can write a class with static variables like in the following example:

class Fruit {
  static orange = 'orange';
  static grape = 'grape';
  static banana = 'banana';
  static apple = 'apple';

  static #secretPear = 'pear';

}

console.log(Fruit.orange);
console.log(Fruit.grape);
console.log(Fruit.banana);
console.log(Fruit.apple);

The example above should output:

orange
grape
banana
apple

If we try to access secretPear from outside the class, like in the following code:

console.log(Fruit.#secretPear);

We’ll get ‘Uncaught SyntaxError: Private field ‘#secretPear’ must be declared in an enclosing class.’

The keyword static is already working with methods in the classes since ES6. For example, we can declare a static method within a class by using the static keyword like in the following code:

class ClassStatic {
  static staticMethod() {
    return 'Static method has been called.';
  }
}

console.log(ClassStatic.staticMethod());

We should get ‘Static method has been called’ from the console.log output. As we can see the staticMethod method was called without instantiating the class ClassStatic class just like we expected. Static methods can also be private, we just add a # sign before the name of the method to make it private. For example, we can write the following code:

class ClassStatic {
  static #privateStaticMethod(){
    return 'Static method has been called.';
  }

  static staticMethod() {
    return ClassStatic.#privateStaticMethod();
  }
}

console.log(ClassStatic.staticMethod());

In the code above, we called the privateStaticMethod from the staticMethod to get the value of the return value from privateStaticMethod in staticMethod. Then when we call staticMethod by running ClassStatic.staticMethod() then we get ‘Static method has been called.’ However, we can’t call privateStaticMethod directly from outside the class, so if we run something like:

class ClassStatic {
  static #privateStaticMethod(){
    return 'Static method has been called.';
  }

  static staticMethod() {
    return ClassStatic.#privateStaticMethod();
  }
}

console.log(ClassStatic.#privateStaticMethod());

Then we will get an error. Also, note that we aren’t using this to access the privateStaticMethod , we used the class name ClassStatic to do it. If we use this to call it, as in this.#privateStaticMethod() , we’ll get an error or undefined depending on the Babel version we’re using. The static keyword for variables is partially supported within browsers. Chromium browsers like Chrome and Opera support it. Also, Node.js supports this keyword. Other browsers do not support it yet, so we’ve to use Babel to convert it into older JavaScript code for it to run on other browsers.

Top Level await

Currently, the await keyword can only be used inside async functions, which are functions that return promises. If we use the await keyword outside of an async function, we’ll get an error like ‘Cannot use keyword ‘await’ outside an async function’ and our program won’t run. Now we can use the await keyword without it being inside an async function. For example, we can use it with the following code:

const promise1 = new Promise((resolve)=>{
  setTimeout(()=> resolve('promise1 resolved'), 1000);
})

const promise2 = new Promise((resolve)=>{
  setTimeout(()=> resolve('promise2 resolved'), 1000);
})

const val1 = await promise1;
console.log(val1);
const val2 =  await promise2;
console.log(val2);

Then when we run this code above in Chrome, we’ll get:

promise1 resolved
promise2 resolved

With top-level await, we can run asynchronous code however we like, and we don’t have to go back to using the long-winded then function chaining with callbacks passed into each then function call. This is very clean and we don’t have to wrap it inside an async IIFE (immediately invoked function expression) to run it if we don’t want to declare a named function.

Another good thing about top-level await is that we can export it directly. This means that when the module exports something that has the await keyword, it will wait for the promise being the await keyword to resolve before running anything. On the surface, it acts as if it’s imported synchronously as usual, but underneath, it actually waits for the promise in the export expression to resolve. For example, we can write:

const promise1 = new Promise((resolve)=>{
  setTimeout(()=> resolve('promise1 resolved'), 1000);
})
export const val1 = await promise1;

When we import module1.js in module2.js :

import { val1 } from './module1';
console.log(`val1);

Then we can see the value of val1 logged as if it’s running synchronously, waiting for promise1 to resolve.

Conclusion

Static fields in classes is a new feature that’s coming soon to browsers and Node.js. It lets us add static fields for classes that do not need an instance of the class to be created to be accessed. They can both be private or public. It’s a handy replacement for enums.

Static methods have existed since ES6 and so it can be used now and has widespread support. Using the await keyword at the top level in regular code and module exports is very handy once it’s a finalized feature. It lets us use await to write asynchronous code outside of async functions, which is much cleaner than using then with callbacks.

Also, it can let us export the resolved value of asynchronous code and then import it and it use it in other modules as if it was synchronous code.