Introduction
ECMAScript¹ (or ES ) is the technical specification of a scripting language, standardized and maintained by ECMA International in ECMA-262 and ISO/IEC 16262. The best known implementations of this language (often referred to as dialects) are JavaScript, JScript and ActionScript (for those who remember the old days of Adobe Flash 😎).
The evolution of the UI/UX (User Interface/User eXperience) of websites has contributed to the growth and diffusion of Javascript, making it the language synonymous with client-side development. In 2009, with the introduction of Node.js, Javascript also “invaded” the server-side development sector, becoming — together with Python — the most used language.
In this article I want to show you the main new features introduced in each release of ECMAScript (and consequently in Javascript).
2009 — ECMAScript 5 (ES5)
5️⃣ Strict Mode: Improves error handling and prevents the use of undeclared variables.
— Browser Support: Chrome 13, Firefox 4, Safari 5.1, Edge 12, IE 10
'use strict' ;
x = 3.14 ; // This will throw an error because x is not declared
5️⃣ Object Methods: New methods for manipulating objects.
— Browser Support: Chrome 5, Firefox 4, Safari 5, Edge 12, IE 9
const obj = {a:1};
Object.defineProperty(obj, 'b', {value:2});
console.log( Object.keys(obj)); // ["a", "b"]
5️⃣ Array Methods: Methods to iterate and manipulate arrays.
— Browser Support: Chrome 5, Firefox 3.5, Safari 5, Edge 12, IE 9
const arr = [1, 2, 3, 4];
const doubled = arr.map( x => x * 2 );
console.log(doubled); // [2, 4, 6, 8]
5️⃣ JSON.parse() and JSON.stringify(): JSON format manipulation.
— Browser Support: Chrome 5, Firefox 3.5, Safari 5, Edge 12, IE 9
//String to JSON
var personString = '{"name":"Alessandra", "age":30}' ;
var personJSONObj= JSON.parse(personString);
console.log(personJSONObj.name ); // Outputs: Alexandra
//JSON to String
var personJSONObj = {name:"Alessia", age:25};
var personString = JSON.stringify(personJSONObj);
console.log(personString); // Outputs: {"name":"Alessia","age":25}
2015 — ECMAScript 6 (ES6) / ES2015
6️⃣ Let and Const: Block-scoped variable declarations.
— Browser Support: Chrome 49, Firefox 44, Safari 10, Edge 14
let x = 10 ;
const y = 20 ;
6️⃣ Arrow Functions: Compact syntax for functions.
— Browser Support: Chrome 45, Firefox 22, Safari 10, Edge 12
const add = (a, b) => a + b;
console.log(add(2, 3)); // 5
6️⃣ Template Literals: Multi-line strings and interpolation ( NB. the string must be enclosed in backtick characters).
— Browser Support: Chrome 41, Firefox 34, Safari 9, Edge 12
const name = 'World' ;
console.log( `Hello, ${name} !` ); // Hello, World!
6️⃣ Classes: Syntax for defining classes.
— Browser Support: Chrome 42, Firefox 45, Safari 9, Edge 13
class Person{
constructor ( name ) {
this.name = name;
}
greet() {
console.log( `Hello, ${ this.name} ` );
}
}
const john = new Person( 'John' );
john.greet(); // Hello, John
6️⃣ Modules: Import and export modules.
— Browser Support: Chrome 61, Firefox 60, Safari 10.1, Edge 16
// In file math.js
export function add( a, b ) {
return a + b;
}
// In another file
import { add } from './math.js' ;
console.log( add(2, 3)); // 5
6️⃣ Promises: Easier asynchronous management.
— Browser Support: Chrome 32, Firefox 29, Safari 8, Edge 12
const promise = new Promise(( resolve, reject ) => {
setTimeout(() => resolve( 'Done!' ), 1000 );
});
promised.then( result => console.log(result)); // Done!
2016 — ECMAScript 7 (ES7) / ES2016
7️⃣ Exponentiation Operator: Exponentiation operator (**
).
— Browser Support: Chrome 52, Firefox 52, Safari 10.1, Edge 14
console.log( 2 ** 3 ); // 8
7️⃣ Array.prototype.includes: Method to check for the presence of an element in an array.
— Browser Support: Chrome 47, Firefox 43, Safari 9, Edge 14
const arr = [1, 2, 3];
console.log(arr.includes(2)); // true
2017 — ECMAScript 8 (ES8) / ES2017
8️⃣ Async/Await: Syntax for asynchronous handling based on Promises.
— Browser Support: Chrome 55, Firefox 52, Safari 10.1, Edge 15
async function fetchData() {
const response = await fetch('https://api.example.com/data');
const data = await response.json();
console.log(data);
}
fetchData();
8️⃣ Object.entries and Object.values: Methods to get keys and values of an object.
— Browser Support: Chrome 54, Firefox 47, Safari 10.1, Edge 14
const obj = {a:1, b:2};
console.log(Object.entries(obj)); // [["a", 1], ["b", 2]]
console.log(Object.values(obj)); // [1, 2]
8️⃣ String Padding: Methods padStartand
and padEnd
for padding strings.
— Browser Support: Chrome 57, Firefox 48, Safari 10.1, Edge 15
console.log('5'.padStart(2, '0')); // "05"
console.log('5'.padEnd(2, '0')); // "50"
2018 — ECMAScript 9 (ES9) / ES2018
9️⃣ Rest/Spread Properties: Object Operators.
— Browser Support: Chrome 60, Firefox 55, Safari 11, Edge 16
const obj = {a:1, b:2, c:3};
const {a, ...rest} = obj;
console.log(rest); // {b:2, c:3}
9️⃣ Asynchronous Iteration: Asynchronous iterators with for-await-of.
— Browser support: Chrome 63, Firefox 57, Safari 12, Edge 79
async function process(array) {
for await(let item of array) {
console.log(item);
}
}
process([1, 2, 3]);
9️⃣ Promise.finally: Method to execute code after a Promise completes.
— Browser Support: Chrome 63, Firefox 58, Safari 11.1, Edge 18
promise
.then(result => console.log(result))then(result => console.log(result))
.catch(error => console.error(error))
.finally(() => console.log('Finished'));
2019 — ECMAScript 10 (ES10) / ES2019
1️⃣0️⃣ Array.prototype.flat and flatMap: flat()
“flattens” an array of arrays into a single array. flatMap()
combines mapping and flattening.
— Browser Support: Chrome 69, Firefox 62, Safari 12, Edge 79
const arr = [1, [2, 3], [4, 5]];
console.log(arr.flat()); // [1, 2, 3, 4, 5]
const arr2 = [1, 2, 3];
console.log(arr2.flatMap(x => [x, x * 2])); // [1, 2, 2, 4, 3, 6]
1️⃣0️⃣ Object.fromEntries: Method to create objects from arrays of key-value pairs.
— Browser Support: Chrome 73, Firefox 63, Safari 12.1, Edge 79
const entries = [['a', 1], ['b', 2]];
const obj = Object.fromEntries(entries);
console.log(obj); // {a:1, b:2}
1️⃣0️⃣ Optional Catch Binding: Ability to omit the catch parameter in errors.
— Browser Support: Chrome 66, Firefox 58, Safari 11, Edge 79
try {
throw new Error( 'Oops' );
} catch { //you used to have to write catch(e)
console.log('Error caught');
}
2020 — ECMAScript 11 (ES11) / ES2020
1️⃣1️⃣ BigInt: Data type to represent very large integers.
— Browser Support: Chrome 67, Firefox 68, Safari 14, Edge 79
const bigInt = 1234567890123456789012345678901234567890n ;
console.log(bigInt); // 1234567890123456789012345678901234567890n
1️⃣1️⃣ Optional Chaining (?.): Allows you to access deeply nested properties without having to explicitly check whether each reference in the chain is null
or undefined
.
— Browser Support: Chrome 80, Firefox 74, Safari 13.1, Edge 80
let user = {name:"Alice", address: {city:"Wonderland"}};
console.log(user?.address?.city ); // "Wonderland"
console.log(user?.contact?.phone ); // undefined
1️⃣1️⃣ Nullish Coalescing Operator (??): Returns the value of its right operand when the left operand is null
or undefined
.
— Browser Support: Chrome 80, Firefox 72, Safari 13.1, Edge 80
let foo = null ?? 'default string' ;
console.log(foo); // "default string"
1️⃣1️⃣ Dynamic Import: Allows you to load modules dynamically, i.e. during code execution, rather than statically at the beginning. This is useful for conditional module loading or module loading. Dynamic Import is particularly useful for improving the performance of web applications, allowing you to load only the necessary code when needed.
— Browser Support: Chrome 63, Firefox 67, Safari 11.1, Edge 79
// Suppose we have a module called 'module.js'
// module.js
export function greet() {
console.log("Hello from the module!");
}
// Main code
async function loadModule() {
const module = await import('./module.js');
module.greet(); // "Hello from the module!"
}
loadModule();
2021 — ECMAScript 12 (ES12) / ES2021
1️⃣2️⃣ Logical Assignment Operators (&&=, ||=, ??=): Combines logical operators with assignment.
— Browser Support : Chrome 85, Firefox 79, Safari 14, Edge 85
let a = 1 ;
to &&= 2 ;
console.log(a); // 2
let b = null ;
b ??= 3 ;
console.log(b); // 3
1️⃣2️⃣ String.prototype.replaceAll(): Replaces all occurrences of a string with another.
— Browser Support : Chrome 85, Firefox 77, Safari 13.1, Edge 85
let str = "Hello world! Hello!" ;
console.log(str.replaceAll("Hello", "Hi")); // "Hi world! Hi!"
1️⃣2️⃣ Numeric Separators: Improves the readability of large numbers by adding underscores ( _ ) as separators.
— Browser Support : Chrome 75, Firefox 70, Safari 13, Edge 79
let largeNumber = 1_000_000_000 ;
console.log(largeNumber); // 1000000000
1️⃣2️⃣ Promise.any(): Returns a promise that resolves as soon as one of the provided promises resolves, or rejects if all promises are rejected.
— Browser Support : Chrome 85, Firefox 79, Safari 14.1, Edge 85
const p1 = Promise.reject('Error');
const p2 = new Promise((resolve) => setTimeout(resolve, 100, 'Success' ));
const p3 = new Promise((resolve) => setTimeout(resolve, 200, 'Another Success'));
Promise.any([p1, p2, p3]).then((value) => {
console.log(value); // "Success"
});
1️⃣2️⃣ WeakRefs: Allows you to create weak references to objects, which do not prevent garbage collection.
— Browser Support : Chrome 84, Firefox 79, Safari 14, Edge 84
let obj = {name:'Alice'};
let weakRef = new WeakRef(obj);
obj = null ; // Object can be garbage collected
console.log(weakRef.deref()); // May return undefined if object was garbage collected
1️⃣2️⃣ FinalizationRegistry: Allows you to register callbacks that are executed when a registered object is garbage collected.
— Browser Support : Chrome 84, Firefox 79, Safari 14, Edge 84
let registry = new FinalizationRegistry((heldValue ) => {
console.log(`Object with held value ${heldValue} was garbage collected`);
});
let obj = {name:'Alice'};
registry.register(obj, 'some value' );
obj = null ; // The object can be collected by the garbage collector
2022 — ECMAScript 13 (ES13) / ES2022
1️⃣3️⃣ Top-level await: Allows you to use await
outside of the functions async
.
— Browser Support: Chrome 89, Firefox 89, Safari 15, Edge 89
// In a module
let response = await fetch('https://api.example.com/data' );
let data = await response.json();
console.log(data);
1️⃣3️⃣ Class Fields: Allows you to define properties directly within a class definition.
— Browser Support: Chrome 72, Firefox 90, Safari 14.1, Edge 79
class MyClass{
myField = 'value' ;
}
let instance = new MyClass();
console.log(instance.myField); // "value"
1️⃣3️⃣ Static Class Fields and Private Methods: Support for static fields and private methods in classes.
— Browser Support: Supported by Chrome 72+, Firefox 90+, Edge 79+, Safari 14+.
class MyClass{
static staticField = 'static' ;
#privateMethod(){
return 'private method' ;
}
callPrivateMethod(){
return this.#privateMethod();
}
}
console.log(MyClass.staticField); // 'static'
const instance = new MyClass();
console.log(instance.callPrivateMethod()); // 'private method'
1️⃣3️⃣ RegExp Match Indices: Adding property indicesto objects RegExp
.
— Browser Support: Supported by Chrome 90+, Firefox 90+, Edge 90+, Safari 15+.
const regex = /a(b)c/ ;
const match = regex.exec('abc');
console.log(match.indices); // [[0, 3], [1, 2]]
1️⃣3️⃣ Object.hasOwn(): A safer way to check if an object owns a specific property.
— Browser Support: Supported by Chrome 93+, Firefox 92+, Edge 93+, Safari 15+.
const obj = {key:'value'};
console.log(Object.hasOwn(obj, 'key')); // true
2023 — ECMAScript 14 (ES14) / ES2023
1️⃣4️⃣ Array.prototype.toSorted: This method works like Array.prototype.sort
, but creates a new sorted array without modifying the original array.
— Browser Support: Supported by Chrome 110+, Firefox 115+, Edge 110+, Safari 16+.
const arr = [3, 1, 4, 1, 5];
const sortedArr = arr.toSorted();
console.log(sortedArr); // [1, 1, 3, 4, 5]
console.log(arr); // [3, 1, 4, 1, 5]
1️⃣4️⃣ Array.prototype.toReversed: Similar to Array.prototype.reverse
, but creates a new reversed array without modifying the original array.
— Browser Support: Supported by Chrome 110+, Firefox 115+, Edge 110+, Safari 16+.
const arr = [1, 2, 3];
const reversedArr = arr.toReversed();
console.log(reversedArr); // [3, 2, 1]
console.log(arr); // [1, 2, 3]
1️⃣4️⃣ Array.prototype.toSpliced: Allows you to create a new array with some elements removed or replaced, without modifying the original array.
— Browser Support: Supported by Chrome 110+, Firefox 115+, Edge 110+, Safari 16+.
const arr = [1, 2, 3, 4];
const splicedArr = arr.toSpliced(1, 2, 5, 6);
console.log(splicedArr); // [1, 5, 6, 4]
console.log(arr); // [1, 2, 3, 4]
1️⃣4️⃣ Array.prototype.with: Creates a new array with a modified element at the specified index.
— Browser Support: Supported by Chrome 110+, Firefox 115+, Edge 110+, Safari 16+.
const arr = [1, 2, 3];
const newArr = arr.with(1, 4);
console.log(newArr); // [1, 4, 3]
console.log(arr); // [1, 2, 3]
1️⃣4️⃣ Hashbang syntax support (#!): Allows you to use hashbang syntax in JavaScript files to specify the interpreter.
— Browser support: Not applicable to browsers, but supported in Node.js environments.
#!/usr/bin/env node
console.log('Hello, world!');
2024 — ECMAScript 15 (ES15) / ES2024
1️⃣5️⃣ Object.groupBy: is a function that allows you to group elements of an array based on a criterion specified by a callback function. It returns an object whose properties correspond to the groups created by the function.
— Browser Support: Supported by Chrome 117+, Firefox 119+, Edge 117+, Safari 17.4+.
const numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9];
const grouped = Object.groupBy(numbers, num => num % 2 === 0 ? 'even' : 'odd');
console.log(grouped); // Output: { odd: [1, 3, 5, 7, 9], even: [2, 4, 6, 8]}
1️⃣5️⃣ Promise.withResolvers: Facilitates the creation of promises that can be resolved or rejected from the outside. Provides an object that contains a promise (promise
) along with functions to resolve (resolve
) or reject (reject
) it.
Previously, the pattern for creating external promises was a bit verbose and not very clear. Promise.withResolvers
simplifies this process, making it easier to manage promises in complex scenarios such as handling timeouts, external resources, or other asynchronous conditions.
— Browser Support: Supported by Chrome 119+, Firefox 121+, Edge 119+, Safari 17.4+.
To better understand this new feature we must first take a step back to ES14. We will use the following code as an example to understand the benefits of Promise.withResolvers
:
// ES14 - ES2023
let resolveFn, rejectFn;
const promise = new Promise((resolve, reject) => {
resolveFn = resolve;
rejectFn = reject;
});
setTimeout(() => resolveFn('Resolved after 1 second' ), 1000);
promised.then(value => console.log(value));
// Output after 1 second: "Resolved after 1 second"
With Promise.withResolvers
, we can do the same thing more simply:
const {promise, resolve, reject} = Promise.withResolvers();
setTimeout(() => resolve('Resolved after 1 second' ), 1000);
promised.then(value => console.log(value));
// Output after 1 second: "Resolved after 1 second"
Another example to better understand its use:
function wait(ms) {
const {promise, resolve, reject} = Promise.withResolvers();
// Resolve the promise after the specified number of milliseconds
setTimeout(() => {
resolve(`Resolved after ${ms} milliseconds`);
}, ms);
return promise;
}
// Use the 'wait' function and wait for the promise to be resolved
wait(2000).then((message) => console.log(message));
// Output after 2 seconds: "Resolved after 2000 milliseconds"
Before we leave, here are some interesting proposals that we might see in the future…
NB The features listed below are still in the Proposal stage
Decorators: New possibilities for using decorators with a clearer and more powerful syntax as @login
this example.
Decorators use a syntax to add annotations or modify the behavior of classes, methods, properties, and parameters. In ES15, decorators are improved to provide clearer syntax and more power.
function log(target, key, descriptor) {
const originalMethod = descriptor.value ;
descriptor.value = function(...args ) {
console.log(`Calling ${key} with`, args);
return originalMethod.apply(this, args);
};
return descriptor;
}
class MyClass {
@log
myMethod(arg) {
console.log(`Inside myMethod with ${arg} `);
}
}
const instance = new MyClass();
instance.myMethod('test');
#Output
Calling myMethod with test
Inside myMethod with test
Records and Tuples: New immutable data types that offer significant advantages in manipulating and managing data structures. These types are designed to be more predictable and efficient, especially in scenarios where immutability is desirable.
const record = #{name:"Alice", age:30};
console.log(record.name); // Alice
console.log(record.age); // 30
// Attempt to edit throws error
// record.name = "Bob"; // TypeError: Cannot assign to read only property 'name' of object
const tuple = #[1, 2, 3];
console.log(tuple[0]); // 1
console.log(tuple[1]); // 2
consoles.log(tuple[2]); // 3
// Attempt to modify throws error
// tuple[0] = 10; // TypeError: Cannot assign to read only property '0' of object
Pipeline Operator: is an operator that allows you to take the output of an expression and pass it as input to the next function. This approach improves the readability of the code when you have multiple subsequent operations that need to be applied to a value.
The operator |>
is used to apply a function to a value, passing the value as the first argument to the function.
function add(x, y) {
return x + y;
}
function multiply(x, y) {
return x * y;
}
function square(x) {
return x * x;
}
/** Example 1 with functions **/
const result = 5
|> (x => add(x, 3)) //5 + 3
|> (x => multiply(x, 2)) //(5 + 3) * 2
|> square; //((5 + 3) * 2) ^ 2
console.log(result); // 128
/** Example 2 with array **/
const numbers = [1, 2, 3, 4, 5];
const result = numbers
|> (arr => arr.map( x => x * 2 )) // [2, 4, 6, 8, 10]
|> (arr => arr.filter( x => x > 5 )); // [6, 8, 10]
console.log(result); // [6, 8, 10]
Follow me #techelopment
Medium: @techelopment
Dev.to: Techelopment
facebook: Techelopment
instagram: @techelopment
X: techelopment
telegram: @techelopment_channel
youtube: @techelopment
whatsapp: Techelopment
References
[1] ECMAScript - Wikipedia
GitHub - sudheerj/ECMAScript-features: ECMAScript features cheatsheet
Modern JavaScript Features in ES13 ES2022
JavaScript | MDN
V8
Can I use... Support tables for HTML5, CSS3, etc
Javascript — What's new with ECMAScript® 2024 (ES15)
⭐ECMAScript version history - Wikipedia
⭐proposals/finished-proposals.md at main · tc39/proposals