JavaScript ES6+ Modern Features

ECMAScript 2015 (ES6) and its subsequent yearly updates introduced a large number of features that transformed how JavaScript is written. This topic provides a comprehensive reference of all the major modern JavaScript features introduced from ES6 onward.

ES6 (ECMAScript 2015)

let and const

let   counter = 0;    // Block-scoped, reassignable
const MAX_VAL = 100;  // Block-scoped, constant

Arrow Functions

const double = n => n * 2;
const add    = (a, b) => a + b;
const greet  = name => `Hello, ${name}!`;

Template Literals

let name = "Ritika";
let age  = 22;
console.log(`${name} is ${age} years old.`);

Destructuring

// Array destructuring
let [a, b, c] = [10, 20, 30];

// Object destructuring
let { name, city = "Unknown" } = { name: "Priya" };

// In function parameters
function show({ name, age }) {
  console.log(`${name}, ${age}`);
}

Default Parameters

function greet(name = "Guest") {
  console.log("Hello, " + name);
}

Spread and Rest Operators

// Spread — expand
let arr    = [1, 2, 3];
let newArr = [...arr, 4, 5];

// Rest — collect
function sum(...nums) {
  return nums.reduce((t, n) => t + n, 0);
}

Classes

class Animal {
  constructor(name) { this.name = name; }
  speak() { console.log(`${this.name} speaks.`); }
}

class Dog extends Animal {
  speak() { console.log(`${this.name} barks!`); }
}

Modules (import/export)

// Export
export const PI = 3.14;
export function area(r) { return PI * r * r; }
export default class Circle {}

// Import
import Circle, { PI, area } from "./shapes.js";

Promises

let p = new Promise((resolve, reject) => {
  setTimeout(() => resolve("Done!"), 1000);
});

p.then(result => console.log(result))
 .catch(err => console.error(err));

Map and Set

let map = new Map([["a", 1], ["b", 2]]);
let set = new Set([1, 2, 2, 3, 3]);

Symbol

let id = Symbol("id");
let obj = { [id]: 42 };
console.log(obj[id]); // 42

for...of Loop

for (let item of ["X", "Y", "Z"]) {
  console.log(item);
}

Iterators and Generators

function* gen() {
  yield 1;
  yield 2;
  yield 3;
}

Proxy and Reflect

let proxy = new Proxy({}, {
  get(target, key) { return key in target ? target[key] : "Not found"; }
});

ES2016 (ES7)

Array.prototype.includes()

let fruits = ["apple", "mango", "banana"];
console.log(fruits.includes("mango")); // true
console.log(fruits.includes("grape")); // false

Exponentiation Operator (**)

console.log(2 ** 10); // 1024
console.log(3 ** 3);  // 27

ES2017 (ES8)

async/await

async function loadData() {
  try {
    let res  = await fetch("https://api.example.com/data");
    let data = await res.json();
    console.log(data);
  } catch (err) {
    console.log(err);
  }
}

Object.entries() and Object.values()

let obj = { a: 1, b: 2, c: 3 };
console.log(Object.entries(obj)); // [["a",1],["b",2],["c",3]]
console.log(Object.values(obj));  // [1, 2, 3]

String.prototype.padStart() and padEnd()

console.log("7".padStart(3, "0"));  // "007"
console.log("5".padEnd(5, "-"));    // "5----"

Object.getOwnPropertyDescriptors()

let descriptors = Object.getOwnPropertyDescriptors({ name: "Raj" });
console.log(descriptors.name.writable); // true

ES2018 (ES9)

Spread and Rest for Objects

let original = { a: 1, b: 2 };
let copy     = { ...original, c: 3 };

function show({ a, ...rest }) {
  console.log(a, rest);  // 1, { b: 2, c: 3 }
}
show(copy);

Promise.finally()

fetch("/api")
  .then(res => res.json())
  .catch(err => console.log(err))
  .finally(() => console.log("Always runs"));

Asynchronous Iteration (for await...of)

async function processStream(asyncIterable) {
  for await (let chunk of asyncIterable) {
    console.log(chunk);
  }
}

ES2019 (ES10)

Array.prototype.flat() and flatMap()

let nested = [1, [2, [3, [4]]]];
console.log(nested.flat(Infinity)); // [1, 2, 3, 4]

let words = ["hello world", "foo bar"];
console.log(words.flatMap(w => w.split(" "))); // ["hello","world","foo","bar"]

Object.fromEntries()

let entries = [["name", "Asha"], ["age", 25]];
let obj = Object.fromEntries(entries);
console.log(obj); // { name: "Asha", age: 25 }

String.prototype.trimStart() and trimEnd()

console.log("  hello  ".trimStart()); // "hello  "
console.log("  hello  ".trimEnd());   // "  hello"

Optional catch Binding

// No need to name the error if not using it
try {
  JSON.parse("{invalid}");
} catch {
  console.log("Parse failed.");
}

ES2020 (ES11)

Optional Chaining (?.)

let user = { address: { city: "Pune" } };
console.log(user?.address?.city);      // Pune
console.log(user?.phone?.number);      // undefined (no error!)

// Works with methods too
console.log(user?.getName?.());        // undefined (no error!)

Nullish Coalescing Operator (??)

let setting = null;
let theme   = setting ?? "light";      // "light" (fallback for null/undefined only)
console.log(theme);

// Difference from || — ?? only triggers on null/undefined, not 0 or ""
let count = 0;
console.log(count || 10);  // 10 (0 is falsy)
console.log(count ?? 10);  // 0  (0 is not null/undefined)

Promise.allSettled()

let results = await Promise.allSettled([
  Promise.resolve("OK"),
  Promise.reject("Error"),
  Promise.resolve("Also OK")
]);
results.forEach(r => console.log(r.status, r.value || r.reason));

BigInt

let bigNum = 9007199254740991n;
console.log(bigNum + 1n); // 9007199254740992n

globalThis

console.log(globalThis); // window in browsers, global in Node.js

ES2021 (ES12)

Logical Assignment Operators

let a = null;
a ??= "default";   // Assign only if a is null/undefined
console.log(a);    // "default"

let b = 0;
b ||= 100;         // Assign only if b is falsy
console.log(b);    // 100

let c = 5;
c &&= 10;          // Assign only if c is truthy
console.log(c);    // 10

String.prototype.replaceAll()

let text = "cat and cat and cat";
console.log(text.replaceAll("cat", "dog")); // "dog and dog and dog"

Promise.any()

let first = await Promise.any([
  Promise.reject("Fail 1"),
  Promise.resolve("Success!"),
  Promise.reject("Fail 2")
]);
console.log(first); // "Success!"

ES2022 (ES13)

Top-Level await (in modules)

// In a module file — no async function wrapper needed
let data = await fetch("https://api.example.com").then(r => r.json());
console.log(data);

Class Private Fields and Methods (#)

class User {
  #password;
  constructor(pass) { this.#password = pass; }
  check(input)      { return input === this.#password; }
}

Array.prototype.at()

let arr = [10, 20, 30, 40, 50];
console.log(arr.at(0));   // 10  (first element)
console.log(arr.at(-1));  // 50  (last element)
console.log(arr.at(-2));  // 40  (second from last)

Object.hasOwn()

let obj = { city: "Delhi" };
console.log(Object.hasOwn(obj, "city"));  // true
console.log(Object.hasOwn(obj, "state")); // false

ES2023 (ES14)

Array findLast() and findLastIndex()

let scores = [40, 85, 60, 90, 55];
console.log(scores.findLast(n => n > 80));        // 90
console.log(scores.findLastIndex(n => n > 80));   // 3

Array toSorted(), toReversed(), toSpliced(), with()

let arr = [3, 1, 2];
let sorted   = arr.toSorted();         // [1, 2, 3] — original unchanged
let reversed = arr.toReversed();       // [2, 1, 3] — original unchanged
let updated  = arr.with(1, 99);        // [3, 99, 2] — original unchanged

Modern Feature Quick Reference Table

FeatureVersionSummary
let/constES6Block-scoped variable declarations
Arrow functionsES6Short function syntax with lexical this
Template literalsES6String interpolation with backticks
DestructuringES6Unpack arrays and objects into variables
Spread / RestES6Expand / collect values with ...
ClassesES6OOP syntax built on prototypes
ModulesES6import / export for code splitting
PromisesES6Handle async results cleanly
async/awaitES8Write async code like sync
Optional chainingES11Safe access to nested properties (?.)
Nullish coalescingES11Fallback for null/undefined (??)
Private fieldsES13Truly private class members (#)
Array.at()ES13Access elements from end with negative index

Key Points to Remember

  • ES6 (2015) was the largest JavaScript update — it introduced classes, modules, promises, arrow functions, and destructuring
  • Optional chaining ?. prevents TypeErrors when accessing nested properties on null/undefined
  • Nullish coalescing ?? provides a fallback only for null and undefined — not for 0 or empty string
  • Logical assignment operators (??=, ||=, &&=) combine checks with assignment
  • Non-mutating array methods (toSorted(), toReversed(), with()) return new arrays without modifying the original
  • Private class fields with # provide true encapsulation in ES2022+
  • Always prefer modern features when targeting current browsers — they are more expressive and safer

Leave a Comment

Your email address will not be published. Required fields are marked *