loading...

7 Exciting New JavaScript Features You Need to Know

gafi profile image Mostafa Gaafar Updated on ・5 min read

This article has been translated to Japanese by @rana_kualu here https://qiita.com/rana_kualu/items/ee7694aa1cd4ae7f4483

JavaScript (or ECMA Script) is an evolving language with lots of proposals and ideas on how to move forward. TC39 (Technical Committee 39) is the committee responsible for defining JS standards and features, and they have been quite active this year. Here is a summary of some proposals that are currently in "Stage 3", which is the last stage before becoming "finished". This means that these features should be implemented in browsers and other engines pretty soon. In fact, some of them are available now.

1. Private fields #

Available in Chrome & NodeJS 12

Yes, you read that right. Finally, JS is getting private fields in classes. No more this._doPrivateStuff(), defining closures to store private values, or using WeakMap to hack private props.

don't touch my garbage

Here's how the syntax looks

// private fields must start with '#'
// and they can't be accessed outside the class block

class Counter {
  #x = 0;

  #increment() {
    this.#x++;
  }

  onClick() {
    this.#increment();
  }

}

const c = new Counter();
c.onClick(); // works fine
c.#increment(); // error

Proposal: https://github.com/tc39/proposal-class-fields

2. Optional Chaining ?.

Ever had to access a property nested a few levels inside an object and got the infamous error Cannot read property 'stop' of undefined. Then you change your code to handle every possible undefined object in the chain, like:

const stop = please && please.make && please.make.it && please.make.it.stop;

// or use a library like 'object-path'
const stop = objectPath.get(please, "make.it.stop");

With optional chaining, soon you'll be able to get the same done writing:

const stop = please?.make?.it?.stop;

Proposal: https://github.com/tc39/proposal-optional-chaining

3. Nullish Coalescing ??

It's very common to have a variable with an optional value that can be missing, and to use a default value if it's missing

const duration = input.duration || 500;

The problem with || is that it will override all falsy values like (0, '', false) which might be in some cases valid input.

Enter the nullish coalescing operator, which only overrides undefined or null

const duration = input.duration ?? 500;

Proposal: https://github.com/tc39/proposal-nullish-coalescing

4. BigInt 1n

Available in Chrome & NodeJS 12

One of the reasons JS has always been terrible at Math is that we can't reliably store numbers larger than 2 ^ 53, which makes it pretty hard to deal with considerably large numbers. Fortunately, BigInt is a proposal to solve this specific problem.

Trump: gonna be HUUUUUGE

Without further ado

// can define BigInt by appending 'n' to a number literal
const theBiggestInt = 9007199254740991n;

// using the constructor with a literal
const alsoHuge = BigInt(9007199254740991);

// or with a string
const hugeButString = BigInt('9007199254740991');

You can also use the same operators on BigInt as you would expect from regular numbers, eg: +, -, /, *, %, ... There's a catch though, you can't mix BigInt with numbers in most operations. Comparing Number and BigInt works, but not adding them

1n < 2 
// true

1n + 2
// 🤷‍♀️ Uncaught TypeError: Cannot mix BigInt and other types, use explicit conversions

Proposal: https://github.com/tc39/proposal-bigint

5. static Fields

Available in Chrome & NodeJS 12

This one is pretty straightforward. It allows having static fields on classes, similar to most OOP languages. Static fields can be useful as a replacement for enums, and they also work with private fields.

class Colors {
  // public static fields
  static red = '#ff0000';
  static green = '#00ff00';

  // private static fields
  static #secretColor = '#f0f0f0';

}


font.color = Colors.red;

font.color = Colors.#secretColor; // Error

Proposal: https://github.com/tc39/proposal-static-class-features

6. Top Level await

Available in Chrome

Allows you to use await at the top level of your code. This is super useful for debugging async stuff (like fetch) in the browser console without wrapping it in an async function.

using await in browser console

If you need a refresher on async & await, check my article explaining it here

Another killer use case is that it can be used at the top level of ES modules that initialize in an async manner (think about your database layer establishing a connection). When such an "async module" is imported, the module system will wait for it to resolve before executing the modules that depend on it. This will make dealing with async initialization much easier than the current workarounds of returning an initialization promise and waiting for it. A module will not know whether its dependency is async or not.

wait for it

// db.mjs
export const connection = await createConnection();
// server.mjs
import { connection } from './db.mjs';

server.start();

In this example, nothing will execute in server.mjs until the connection is complete in db.mjs.

Proposal: https://github.com/tc39/proposal-top-level-await

7. WeakRef

Available in Chrome & NodeJS 12

A weak reference to an object is a reference that is not enough to keep an object alive. Whenever we create a variable with (const, let, var) the garbage collector (GC) will never remove that variable from memory as long as its reference is still accessible. These are all strong references. An object referenced by a weak reference, however, may be removed by the GC at any time if there is no strong reference to it. A WeakRef instance has a method deref which returns the original object referenced, or undefined if the original object has been collected.

This might be useful for caching cheap objects, where you don't want to keep storing all of them in memory forever.


const cache = new Map();

const setValue =  (key, obj) => {
  cache.set(key, new WeakRef(obj));
};

const getValue = (key) => {
  const ref = cache.get(key);
  if (ref) {
    return ref.deref();
  }
};

// this will look for the value in the cache
// and recalculate if it's missing
const fibonacciCached = (number) => {
  const cached = getValue(number);
  if (cached) return cached;
  const sum = calculateFibonacci(number);
  setValue(number, sum);
  return sum;
};

This is probably not a good idea for caching remote data as it can be removed from memory unpredictably. It's better to use something like an LRU cache in that case.

Proposal: https://github.com/tc39/proposal-weakrefs


That's it. I hope you're as excited as I am to use these cool new features. For more details on these proposals and others that I didn't mention, keep an eye on TC39 proposals on github

Discussion

markdown guide
 

Nice list! Really looking forward to these. I still think private fields prefixed with "#" is crazy and shouldn't have been accepted, but the rest are cool and I can't wait to use them!
Thanks for sharing!

 

I don't get this one either. Why not conform and use private like in both Java, and TypeScript.

This one is mind boggling.

 

I had the same feeling at first. Then I read the reasons behind it and it made some sense. Long story short: in a dynamically typed language, giving the engine a hint whether the property you're trying to access is public or private makes it much easier to implement without exposing details of internal private fields. Here's the reasoning behind it github.com/tc39/proposal-private-f...

Another advantage of it is that linters can also understand if you're trying to access a private property outside its class and warn you, which would be impossible without a special identifier

 

Totally agree. Didn't look at specs to be honest, but why it wasn't problem to introduce static keyword and it is a problem indeed with private? 🤔

 

Agreed on the private field prefix. I kinda hope typescript leaves that one out, but they probably have to include it or they would no longer be a superset of js.

 

Good write-up! I'm especially looking forward to nullish coalescing, as it would've solved an annoying but I just had.

I heard about optional chaining from Kyle Simpson, and it looks useful! I'll likewise enjoy trying that out.

I'm personally not thrilled about private or static stuff, but much like classes, I know they'll help passerby JS developers who already use JS as an OO language. As the language of the web, it's probably better if developers of all types encounter as little friction as possible working with JS.... but I'm still scrunching up my nose at it.

 

I think now that JS has classes, the private and static keywords/symbols are only a natural next step.

Still, I have to agree with some others about the # symbol for private. That's bizarre to me.

On the other hand though, I guess you'll get some kind of indication from outside the class that what you're trying to use is private. Hopefully it's helpful in that regard.

 

New features are coming with Chrome 🤔

 

BigInt in particular is welcome - and the restrictions are there for technical implementation reasons, but in practice they matter less, since you can always convert a Number explicitly to a BigInt. As for the others, they solve some pain points, some specific to JS. Look forward to seeing how people use them.

 

2, 3 and 6.

thepracticaldev.s3.amazonaws.com/i...

PS: Small grammar thingies:
{
"as long as it's reference" : "its",
"We with optional chaining" : undefined
}

 
 

For us using Typescript these features are not new.

Great nevertheless

 

Such a helpful article. I learned a lot. Thank you

 

Some I didn't know about, fantastic!

 
 

I was not awere of weak refs. This might be a great performance improvement for modern web applications.

Thanks for sharing!

 
Sloan, the sloth mascot Comment marked as low quality/non-constructive by the community View code of conduct

Fabulous article, I’ve added new vlog too about ES6 features which include:
Array Destructing
Array Spreading
Object Destructing
Object Spreading
You can check it on youtu.be/Z5FxVKRfocw

  • If you found it informativ — Please hit Like, Share and Subscribe channel*