ECMAScript 2024 brings some exciting new features to help developers. Here are 10 of the most notable changes along with examples and use cases.
Top-level await allows awaiting promises at the top level of modules. This simplifies asynchronous logic in modules.
// index.js
let data = await fetch('/data.json');
console.log(data);
Previously we had to wrap top-level code in an async IIFE. Top-level await makes code cleaner.
Class fields let us declare fields directly in classes without getter/setter syntax. Private fields and methods use a # syntax.
class Customer {
#name
constructor(name) {
this.#name = name;
}
#getInfo() {
return `Name is ${this.#name}`;
}
greet() {
console.log(this.#getInfo());
}
}
This is a more straightforward way to define classes compared to ES6 syntax.
The matches method provides cleaner control flow than if/else chains by pattern matching input values.
switch(checkType(value)) {
case {kind: "number", number: 42}:
return "The Answer";
case {kind: "string"}:
return value;
}
It improves readability of complex conditional logic.
Import assertions allow validating imported values, like ensuring an import is a function.
import { parse } from 'path/to/parser.js';
assert.function(parse);
This provides self-documenting code and catches errors early.
Weak references allow holding onto objects without preventing garbage collection.
const wr = new WeakRef(node);
node = null;
// GC can collect node
console.log(wr.deref());
Useful for caches, proxies, and other scenarios where strong references aren't needed.
Class fields with public and private accessors and methods. Private methods start with # syntax.
class Point {
#x = 0;
constructor(x) {
this.#x = x;
}
#timesTwo() {
return this.#x * 2;
}
publicTwice() {
return this.#timesTwo();
}
}
Encapsulates details and avoids inheritance issues.
// math.js
export const e = await loadNumericConstant('./e.json');
Modules can now have asynchronous top-level code, avoiding workers or IIFEs.
Collections that allow holding onto objects without preventing garbage collection.
const cache = new WeakMap();
function getKey(obj) {
return cache.get(obj) || newName(obj);
}
Useful for caching, identifiers and other non-owning references.
Class fields can be initialized using getter/setter syntax:
class Point {
get x() { return 0; }
set x(v) { this.#x = v; }
#x;
}
Supports gradual migration from ES5 style classes.
export * as math from './math.js';
Concise way to re-export all exports under a single name.