ECMAScript - A collection of the main new features of each version

Techelopment - Sep 21 - - Dev Community

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
Enter fullscreen mode Exit fullscreen mode

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"]
Enter fullscreen mode Exit fullscreen mode

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]
Enter fullscreen mode Exit fullscreen mode

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}
Enter fullscreen mode Exit fullscreen mode

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 ;
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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!
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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!
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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();
Enter fullscreen mode Exit fullscreen mode

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]
Enter fullscreen mode Exit fullscreen mode

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"
Enter fullscreen mode Exit fullscreen mode

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}
Enter fullscreen mode Exit fullscreen mode

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]);
Enter fullscreen mode Exit fullscreen mode

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'));
Enter fullscreen mode Exit fullscreen mode

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]
Enter fullscreen mode Exit fullscreen mode

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}
Enter fullscreen mode Exit fullscreen mode

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'); 
}
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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"
Enter fullscreen mode Exit fullscreen mode

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();
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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!"
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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"
 });
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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);
Enter fullscreen mode Exit fullscreen mode

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"
Enter fullscreen mode Exit fullscreen mode

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'
Enter fullscreen mode Exit fullscreen mode

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]]
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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]
Enter fullscreen mode Exit fullscreen mode

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]
Enter fullscreen mode Exit fullscreen mode

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]
Enter fullscreen mode Exit fullscreen mode

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]
Enter fullscreen mode Exit fullscreen mode

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!');
Enter fullscreen mode Exit fullscreen mode

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]}
Enter fullscreen mode Exit fullscreen mode

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.withResolverssimplifies 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"
Enter fullscreen mode Exit fullscreen mode

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"
Enter fullscreen mode Exit fullscreen mode

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"
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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]
Enter fullscreen mode Exit fullscreen mode

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

. . . . . . . . . . . . . . . . . . . . . . . . . .