ES2020 features for web developers

ES2020 features for web developers

Robin Blaauw

Robin Blaauw

Ever since the release of ECMAScript 6 in 2015 the language has been constantly evolving and maturing. New features are being proposed and developed regularly. Proposed features go through 4 stages: proposal, draft, candidate and finished. Finished proposals are added to the language in an annual update. In 2020 new exciting features will be available for us to use in our projects. If you are a web developer, here’s a list of 4 features you should look forward to start using.

Nullish Coalescing Operator

The Nullish Coalescing Operator, written with double question marks ??, is a logical operator that returns its right handed operand if the outcome of the left handed operand is null or undefined. You might think, don’t we already have an operator that does this called the “or” operator?
Where the or operator, written with double lines ||, is different is that it returns the right handed operand if the left handed operand is false. This a very important distinction.

Look at the following lines:

undefined || 'default'
null || 'default'
false || 'default'
‘’ || 'default'
0 || 'default'

All of these return the string default. This could cause problems if we only wanted to return default if the outcome was null or undefined. Before the nullish coalescing operator there was a way to do this, but it required more type checking and more writing. Using the nullish coalescing operator allows you to better predict the outcome and avoid unwanted behaviour.

a ?? 'default'
a !== undefined && a !== null ? a : 'default'

These 2 lines do the exact same. The first line is more readable and less prone to unwanted behaviour due to less type checking. The Nullish coalescing operator is perfect for adding a default value if you are unsure if a variable is defined or has a value.

Optional Chaining

With the optional chaining operator you are able to check deep nested properties without having to worry about it all being valid. Before this feature, in order to check deep nested properties it required you to validate the steps in between. Consider the following object:

let company = {
    employees: {
        john: {
           age: 28
       }
    }
}

In order to access the age of nested object john before Optional Chaining you would have to write out each step like this:

company && company.employees && company.employees.john && company.employees.john.age

As you might expect this would get out of hand pretty fast if you had to access deeper nested items. With the new syntax all you need to do is add a ? before each property. With the new syntax the same line of code would look like this

company?.employees?.john?.age

Currently if we try to access a property that is not found it gives back undefined. However, if we combine optional chaining with the nullish coalescing operator, that we talked about previously, we can create a default value. Imagine we’d like to know how many hours a week John works, and the default in his company is 40, we could write something like this:

company?.employees?.john?.workhours ?? 40

It checks if the object john has a value called workhours. If it’s not found it returns the default value 40.

Dynamic imports

If you’re a web developer that works in a team, or on large projects, there’s a good chance you work with imports a lot. They have been around since 2015, when javascript received one of the biggest updates to the language. Although imports are very handy, they do have some limits.

  • Imports are limited to the top level of a file
  • They can’t be loaded conditionally inside if statements
  • The name of the package can’t be determined at execution time

5 years later we can look forward to a new addition to the way we use imports, dynamic imports. Dynamic imports solve the limitations we previously faced. Their syntax is a bit different and they work within modules.

The way we currently use imports looks like this. These should look familiar, they can always be found at the top of a file.

import defaultExport from "module-name";
import * as name from "module-name";
import { exportable } from "module-name";

The new dynamic import looks like a function expression. It loads the module and returns a promise that resolves into a module object that contains all its exports. It can be declared and called from any place in the code.

Here’s an example of a module being specified and called

const moduleSpecifier = "./module.js";
import(moduleSpecifier).then(module => module.foo());

It’s also possible to use const module = await import(modulePath) if inside an async function. The syntax for importing and using would look like this

let { func1, func2 } = await import("./modules.js");

func1();
func2(); 

Dynamic imports will give us more control over when and where we want to import our modules. It will help us keep a better overview and improve overall performance of our applications and websites.

Class field declarations

In 2020 we will most likely see the coming of new static features to javascript classes. A static method is a method you define on a class but is not part of the instantiated object that is created. It does not require an instance of the class to be created in order to use it. 3 new changes we can expect are

  • Static public fields
  • Static private fields
  • Static private methods

Static public fields

Public fields are useful when you want a field to exist only once per class and not on every class instance you create. Static public fields are declared with the static keyword.

class Example {
    static staticClassProperty = "I’m a string";
} 

console.log(Example.staticClass) //output of this is “I’m a string”

When initializing fields, using this refers to the class under construction. In this case using this would always refer to example.

class Example {
    static staticField = "I’m a string";
    static subField = this.staticField + " subfield";
}

console.log(Example.subField) //output of this is "I’m a string subfield”

But what if we have a subclass and we would like to access the static field “subfield”?. For that we can use super to access the so called superclass. Let’s take a look at how this works.

class Example {
    static staticField = "I’m a string";
    static subField = this.staticField + " subfield";
}

class ExampleExtend extends Example {
    static extendedField = super.subField;
}

console.log(ExampleExtend.extendedField) //output of this is "I’m a string"

In this case our superclass is example. Inside our subclass “exampleExtend” we can call the super method to reference to our superclass and use its static fields. But what if we didn’t want anything from the outside to be able to access the static fields? For this we have private fields.

Static private fields

In almost all ways static private fields are the same as static public fields. They are however only accessible from inside the class itself.

To make a field a private field you simply just have to at a # in front of the name. If we use our previous example and would want to make the first static class private, because do not want to be able to reach it from outside our class, we could simple add a # in front of the class.

class Example {
    static #staticField = "I’m a string";
    static subField = this.#staticField + " subfield";
}

console.log(Example.subField) // outputs "I’m a string subfield"

Making class fields private ensures stronger encapsulation and prevents later hiccups by depending on internal fields, as the structure may change in different versions.

Note: you are not able to access example.#staticField outside of example. It will give you an error.

static private methods

The same way static public fields and static private fields are very alike, static private methods and static public methods are a lot alike. As you would expect from the previous, the main difference is that you can’t access the static private method from outside the
class.

class Msg {
    static staticField = this.#privateMethod()
 
    static #privateMethod() {
        return "I’m a private method!"
    }
}

console.log(Msg.staticField) //outputs "I’m a private method!"

In conclusion

The features ES2020 will provide us with will make our life as web developers easier. It will provide us with more structure and improve the quality of our code. They will help us avoid unexpected behaviours and it will improve the readability of our code.

Robin Blaauw
Robin Blaauw

Front-end Developer