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
| Feature | Example | Learned in |
|---|---|---|
let and const | const rate = 18; | Variables |
| Template literals | `Hi ${name}` | Variables |
| Arrow functions | (a, b) => a + b | Functions |
| Default parameters | function greet(name = 'friend') | Functions |
for…of | for (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,
...numbersgathers 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 existsClasses 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
- developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals
- developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring
- developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_syntax
- developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Optional_chaining
- developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Modules
