Lesson 11 of 12

Modern JavaScript (ES6+) Features

In 2015 JavaScript received its biggest update ever, officially called ECMAScript 2015 and usually known as ES6. Since then a smaller update has arrived every year. Together these changes made the language shorter, safer and easier to read. You have already been using several ES6 features in this track; this lesson collects them in one place and adds a few new ones you will see in every modern codebase.

Every one of these ES6 features is supported by all current browsers, so you can use them without any build tools.

Quick recap: ES6 features you already know

FeatureExampleLearned in
let and constconst rate = 18;Variables
Template literals`Hi ${name}`Variables
Arrow functions(a, b) => a + bFunctions
Default parametersfunction greet(name = 'friend')Functions
for…offor (const city of cities)Loops
Shorthand properties and methods{ name, price, total() { … } }Objects

Two points deserve a second look. Template literals can span several lines and contain any expression inside ${ } – a calculation, a function call or a ternary. And arrow functions do not have their own this; they use the this of the surrounding code. That makes them perfect for callbacks, but wrong for object methods that need this.

Destructuring

Destructuring unpacks values from arrays or properties from objects into separate variables in one line. With objects, you pick properties by name; with arrays, you pick items by position. You can rename variables and give default values for missing data.

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <title>Destructuring</title>
  <style>
    body { font-family: system-ui, sans-serif; padding: 16px; line-height: 1.5; }
  </style>
</head>
<body>
  <pre id="out"></pre>

  <script>
const booking = {
  guest: 'Aishwarya',
  hotel: 'Seaside Inn',
  nights: 3,
  city: 'Puducherry'
};

// Object destructuring: pick properties by name
const { guest, nights, city: location, breakfast = 'not included' } = booking;

// Array destructuring: pick items by position
const ratings = [4.8, 4.5, 3.9];
const [best, second] = ratings;

// Destructuring in function parameters
function label({ hotel, nights }) {
  return `${hotel} for ${nights} night${nights === 1 ? '' : 's'}`;
}

document.getElementById('out').textContent =
  `Guest: ${guest}
Stay: ${label(booking)} in ${location}
Breakfast: ${breakfast}
Top two ratings: ${best} and ${second}`;
  </script>
</body>
</html>

Destructuring in parameters is very common: a function that receives an options object can list exactly the properties it uses. You also saw array destructuring with Object.entries() in the Objects lesson: for (const [key, value] of …).

Spread and rest: the three dots

The same ... syntax does two opposite jobs, depending on where it appears:

  • Spread expands an array or object into individual items. Use it to copy ([...list], { ...settings }), merge ([...a, ...b]), or pass array items as function arguments (Math.max(...prices)).
  • Rest collects several items into one array or object. In a function’s parameters, ...numbers gathers any number of arguments; in destructuring, it gathers “everything else”.
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <title>Spread and rest</title>
  <style>
    body { font-family: system-ui, sans-serif; padding: 16px; line-height: 1.5; }
  </style>
</head>
<body>
  <pre id="out"></pre>

  <script>
// Spread: merge arrays and copy-and-update objects
const south = ['Chennai', 'Bengaluru'];
const coast = ['Kochi', 'Visakhapatnam'];
const allCities = [...south, ...coast];

const defaults = { theme: 'light', fontSize: 16 };
const userPrefs = { ...defaults, theme: 'dark' };   // later keys win

// Rest: gather any number of arguments
function sumAll(...amounts) {
  return amounts.reduce((total, n) => total + n, 0);
}

// Rest in destructuring
const [first, ...others] = allCities;

document.getElementById('out').textContent =
  `All cities: ${allCities.join(', ')}
Prefs: ${JSON.stringify(userPrefs)}
Sum: ${sumAll(120, 45, 300, 15)}
First: ${first}; others: ${others.join(', ')}
Highest: ${Math.max(...[12, 99, 47])}`;
  </script>
</body>
</html>

Tip: Spread makes a shallow copy: nested arrays and objects inside are still shared with the original. Use structuredClone() when you need a deep copy.

Optional chaining and nullish coalescing

Data from forms and servers is often incomplete. Reading user.address.pincode crashes if address is missing. The optional chaining operator ?. stops and returns undefined instead of throwing an error when the value on its left is null or undefined. Pair it with ?? (from Operators) to supply a fallback.

const user = { name: 'Senthil' };   // no address yet

user.address.pincode;               // TypeError!
user.address?.pincode;              // undefined
user.address?.pincode ?? 'Not set'; // 'Not set'
user.getAge?.();                    // undefined – calls only if the method exists

Classes and other handy additions

ES6 also introduced the class keyword, a tidy way to create many objects of the same shape – for example class Product { constructor(name, price) { this.name = name; this.price = price; } } followed by new Product('Kurta', 899). Classes are more common in larger applications and frameworks, so it is enough to recognise them for now.

Smaller yearly updates added many helpers you have already met: includes(), at(), Object.entries(), toSorted(), the ** operator and structuredClone(). When you read older code, you will often find long workarounds that one of these now replaces.

Modules: import and export

As projects grow, one huge script becomes hard to manage. ES modules let you split code into files that share values explicitly. A file marks what it offers with export, and another file pulls those values in with import. Load the entry file with <script type="module">. Modules are deferred automatically, run in strict mode, and keep their top-level variables private instead of making them global.

// utils.js
export const GST_RATE = 18;
export function withGst(price) {
  return price + price * GST_RATE / 100;
}

// main.js – loaded with <script type="module" src="main.js"></script>
import { withGst, GST_RATE } from './utils.js';

document.querySelector('#price').textContent =
  `Rs. ${withGst(500)} (incl. ${GST_RATE}% GST)`;

Watch out: Modules do not work when you open an HTML file directly from your disk (a file:// address), because browsers block module loading there for security. Run a small local server – for example the Live Server extension in VS Code – while you develop.

The last big modern feature is a cleaner way to work with tasks that take time, such as loading data from a server. That is the topic of the final lesson: Fetch and Async JavaScript.

Further reading

Key takeaways

  • ES6 (2015) and the yearly updates since then made JavaScript shorter and safer.
  • Destructuring unpacks object properties and array items into variables.
  • Spread (...) expands arrays and objects; rest (...) collects items into one.
  • ?. reads nested properties safely; ?? provides a fallback for null or undefined.
  • ES modules use export and import, loaded with a script tag that has type="module".

Quick quiz

Check what you learned – pick an answer.

1. Given const { name, age = 30 } = { name: 'Ravi' }; what is age?

2. What does [...[1, 2], ...[3, 4]] produce?

3. If order is {}, what is order.customer?.name ?? 'Guest'?

Practice exercise

Write a function describeOrder that takes an order object and uses destructuring in its parameter to read id, items (an array) and an optional coupon. Return a template-literal sentence with the order id, the number of items and the coupon, or "no coupon" when it is missing. Show the result for two orders, one with a coupon and one without.

Show a hint

Give the coupon a default value directly in the destructuring pattern: { id, items, coupon = 'no coupon' }.

Show the solution
<pre id="out"></pre>
<script>
  function describeOrder({ id, items, coupon = 'no coupon' }) {
    return `Order #${id}: ${items.length} item(s), ${coupon}`;
  }

  const first = { id: 101, items: ['Kurta', 'Dupatta'], coupon: 'DIWALI10' };
  const second = { id: 102, items: ['Sandals'] };

  document.getElementById('out').textContent =
    `${describeOrder(first)}
${describeOrder(second)}`;
</script>

Progress is saved in this browser only.