ES6+ Modern JavaScript
Reviewed & published by Brayan K
ES6 (ECMAScript 2015) and later versions are modern updates to JavaScript that add features like let/const, arrow functions, template literals, destructuring, classes, and modules to write cleaner, more powerful code.
Part of the free JavaScript course at LearnCodingFast โ hands-on lessons with examples you run in your browser, plus practice exercises and a quick quiz.
What You'll Learn in This Lesson
- Destructure arrays and objects cleanly
- Spread and rest operators (...)
- Template literals and multiline strings
- Arrow functions and implicit returns
- Optional chaining (?.) and nullish coalescing (??)
- ES6 modules, classes, and modern syntax
๐ก Running Code Locally: While this online editor runs real JavaScript, some advanced examples may have limitations. For the best experience:
- Download Node.js to run JavaScript on your computer
- Use your browser's Developer Console (Press F12) to test code snippets
- Create a .html file with <script> tags and open it in your browser
๐ Real-World Analogy: ES6+ is like upgrading from a flip phone to a smartphone:
- โข Same core purpose (making calls / writing code)
- โข But with way more features that make life easier
- โข Once you learn the new features, you'll never go back!
๐ Introduction to Modern JavaScript (ES6+)
JavaScript changed forever in 2015 with the release of ECMAScript 2015 (ES6). Since then, dozens of new features have been added, making JavaScript more:
| ES6+ Feature | What It Does | Why It Matters |
|---|---|---|
| Arrow Functions | Shorter function syntax | Cleaner, more readable code |
| Destructuring | Extract values easily | Less boilerplate code |
| Template Literals | String interpolation | Easier string building |
| Spread/Rest | Expand or collect values | Flexible data handling |
| Modules | Import/export code | Organized, reusable code |
Modern JavaScript is what developers use today for:
- Full-stack apps
- Browser extensions
- Desktop apps
This lesson teaches you every major ES6+ feature with real examples, in-depth explanations, best practices, and practical exercises.
By the end of this lesson, you'll write code like a real modern JavaScript engineer.
๐ฅ 1. Destructuring (Arrays & Objects)
Destructuring lets you unpack values from arrays and objects into clean variables.
const arr = [1, 2, 3];
const a = arr[0];
const b = arr[1];const [a, b] = [1, 2];Array Destructuring
const numbers = [10, 20, 30, 40];
const [first, second] = numbers;
console.log(first); // 10
console.log(second); // 20Rest Operator in Destructuring
const [a, b, ...rest] = [1, 2, 3, 4, 5];
console.log(rest); // [3,4,5]Object Destructuring
const person = {
name: "Alice",
age: 30,
city: "New York"
};
const { name, age } = person;Renaming Variables
const { name: username } = person;
console.log(username);Default Values
const { country = "USA" } = person;๐ 2. The Spread Operator (...)
Spread "expands" arrays or objects.
Combine Arrays
const arr1 = [1,2];
const arr2 = [3,4];
const combined = [...arr1, ...arr2];Copy Arrays
const copy = [...arr1];Spread in Objects
const base = { a: 1, b: 2 };
const extended = { ...base, c: 3 };๐งต 3. Template Literals
Template literals replaced the messy + string concatenation system.
Multiline Strings
const text = `
Line 1
Line 2
Line 3
`;๐น 5. Arrow Functions
Arrow functions are cleaner, shorter, and preferred in modern JS.
function add(a,b){ return a+b; }const add = (a,b) => a + b;Arrow Function Features
Implicit return
const double = x => x * 2;Great for callbacks (React, event handlers, arrays).
๐๏ธ 6. Enhanced Object Literals
Shorthand Properties
const x = 10, y = 20;
const point = { x, y };Method Shorthand
const math = {
add(a,b){ return a+b; }
};๐ 7. Optional Chaining (?.)
Prevents crashes when accessing deep values.
const city = data?.user?.address?.city;If any layer is missing โ returns undefined safely.
๐ซ๏ธ 8. Nullish Coalescing (??)
const username = input ?? "Guest";|| treats empty strings or 0 as "false", ?? treats only undefined or null as empty.
๐ 9. Rest Parameters
Collect an unlimited number of arguments:
function sum(...nums){
return nums.reduce((a,b)=>a+b,0);
}๐งช Worked Example โ Seven Features in One Small Program
You have now seen each feature on its own. Here they are working together on the kind of half-complete data a real API sends you. Read it top to bottom first โ every non-obvious line has a comment saying what it prints and why โ then press Run and check the output against the list at the bottom.
One quirk of this editor worth knowing: when you console.log an array or an object it is printed as indented JSON across several lines, not on one line. That is the editor being helpful, not your code misbehaving.
๐พ 10. Modules (import/export)
Export
export function greet(){}Import
import { greet } from './utils.js';Modules allow clean project structure for real apps.
๐ 11. Classes (ES6 OOP Syntax)
Modern, cleaner way to write object-oriented JS:
class Person {
constructor(name){
this.name = name;
}
}๐ฎ Real Examples (Modern Apps Use These Daily)
React Components
const Component = ({ title="Untitled", items=[] }) => (
<div>
<h1>{title}</h1>
{items.map(i => <p>{i}</p>)}
</div>
);Node.js APIs
app.get("/user", (req,res) => {
res.json({ message: "Hello!" });
});Game Logic
const player = { ...defaultStats, hp: 200 };Data Cleaning
const clean = users
.filter(u => u.active)
.map(u => u.name);Modern JS is everywhere.
๐ Best Practices for ES6+
โ๏ธ Always use const or let
โ๏ธ Use arrow functions for callbacks
Cleaner + no this binding issues.
function greet({name}){...}โ๏ธ Spread when copying arrays & objects
Never mutate original data.
โ๏ธ Use template literals for all strings
โ๏ธ Optional chaining for safe access
Avoids crashes in large apps.
๐ง Mini-Projects with ES6+
1. Create a user profile builder
- destructuring
- template literals
- object spreading
- arrow functions
2. Build a settings manager
Using default parameters + object spread:
const defaultConfig = {...}4. Create a safe API fetcher
Use optional chaining and nullish coalescing.
๐ฏ Your Turn โ Fill In the Modern Syntax
Reading modern syntax is easy; writing it is the bit that sticks. Four blanks below, one per feature, everything else done for you. Fill them in and press Run โ the expected output is at the bottom of the code so you can check yourself.
// ๐ฏ YOUR TURN - modernise this code
// Everything is written for you except the four blanks marked ___
const order = {
id: 5012,
customer: "Ravi",
items: ["keyboard", "mouse"],
shipping: { city: "Leeds" }
};
// ๐ 1) DESTRUCTURE id, customer and items out of 'order' in this one line.
// Also declare 'discount' with a DEFAULT of 0 - 'order' has no discount key.
const { ___ } = order;
// ๐ 2) Build the message with a TEMPLATE LITERAL (backticks), not + signs.
// It has to read exactly: Order 5012 for Ravi: 2 item(s)
// Hint: items.length gives you the 2.
const message = ___;
console.log(message);
// ๐ 3) SPREAD 'order' into a copy, then add status: "shipped".
// The original must not change.
const shipped = { ___, status: "shipped" };
console.log(shipped.status);
console.log(order.status); // proves the original was not mutated
// ๐ 4) Write 'label' as an ARROW FUNCTION taking one item and
// returning it in capitals. Hint: .toUpperCase()
const label = ___;
console.log(order.items.map(label).join(" + "));
console.log("Discount applied:", discount);
console.log("City:", order?.shipping?.city ?? "Unknown");
// โ
Expected output:
// Order 5012 for Ravi: 2 item(s)
// shipped
// undefined
// KEYBOARD + MOUSE
// Discount applied: 0
// City: LeedsBlank 1 catches most people. You need four names inside the braces, and one of them (discount) needs = 0 after it because the object has no such key.
๐ฏ Practice Challenge
Try to complete all:
- 1๏ธโฃ Use destructuring - Extract values from: an array, an object, a nested object
- 2๏ธโฃ Combine arrays using spread - Create combined = [...a,...b].
- 3๏ธโฃ Use template literals - Create a multi-line formatted message.
- 4๏ธโฃ Write three arrow functions - multiply, square, convert minutes โ seconds
- 5๏ธโฃ Use default parameters - Create a function with 2 defaults.
- 6๏ธโฃ Use optional chaining - Access a nested property safely.
๐ Mini-Challenge: Settings Manager
No blanks now โ a brief, an outline and a test harness. The last line of the expected output is the one that really tests you: if DEFAULTS has changed, you mutated it instead of copying it.
// ๐ฏ MINI-CHALLENGE: a settings manager
//
// Brief: write applySettings(userSettings) so it merges the user's choices on
// top of these defaults WITHOUT mutating either object, then returns a one-line
// report. This is exactly how real apps handle config.
const DEFAULTS = { theme: "dark", fontSize: 14, language: "en", autosave: true };
// Outline - no logic filled in, that part is yours:
//
// const applySettings = (userSettings = {}) => {
// 1. build 'merged' by spreading DEFAULTS first, then userSettings
// (order matters - whatever comes last wins)
// 2. destructure theme, fontSize, language and autosave out of 'merged'
// 3. return a template literal shaped exactly like:
// theme=dark size=14px lang=en autosave=true
// };
//
// Until you have written it, running this throws
// "ReferenceError: applySettings is not defined" - that is expected, not a bug.
// your code here
// --- test harness: do not change anything below this line ---
console.log(applySettings());
console.log(applySettings({ theme: "light", fontSize: 18 }));
console.log(applySettings({ autosave: false }));
console.log("DEFAULTS untouched:", DEFAULTS.theme, DEFAULTS.fontSize);
// โ
Expected output:
// theme=dark size=14px lang=en autosave=true
// theme=light size=18px lang=en autosave=true
// theme=dark size=14px lang=en autosave=false
// DEFAULTS untouched: dark 14The default parameter userSettings = {} is what lets applySettings() be called with no arguments at all. Without it, spreading undefined would still work, but destructuring from it would not.
๐ End of the Lesson
This completes your modern JavaScript fundamentals. Once you master ES6+, you can build real apps confidently.
๐ Quick Reference โ ES6+ Features
| Feature | Syntax Example |
|---|---|
| Arrow Function | (a,b) => a+b |
| Destructuring | const {name} = user; |
| Spread | [...oldArr, 4, 5] |
| Template Literal | |
| Optional Chain | user?.address?.city |
Lesson Complete โ ES6+ Modern JS!
You've leveled up! You now write modern, clean, efficient JavaScript using features that professional developers use every day.
Practice quiz
What does const [a, b, ...rest] = [1, 2, 3, 4, 5] make rest equal to?
- [3, 4, 5]
- [1, 2]
- [4, 5]
- 5
Answer: [3, 4, 5]. The rest element collects all remaining values after a and b into a new array: [3, 4, 5].
What is the result of [...[1, 2], ...[3, 4]]?
- [[1,2],[3,4]]
- [1, 2, 3, 4]
- [1, 2]
- '1234'
Answer: [1, 2, 3, 4]. Spread expands both arrays into a single combined array [1, 2, 3, 4].
Given const base = { a: 1, b: 2 }, what is { ...base, c: 3 }?
- { a: 1, b: 2 }
- { c: 3 }
- { a: 1, b: 2, c: 3 }
- An error
Answer: { a: 1, b: 2, c: 3 }. Object spread copies base's properties and adds c, producing { a: 1, b: 2, c: 3 }.
With const double = x => x * 2, what does double(5) return?
- 5
- 10
- 25
- undefined
Answer: 10. The arrow function has an implicit return of x * 2, so double(5) is 10.
What does the rest-parameter sum from sum(...nums) return for sum(1, 2, 3, 4, 5)?
- 120
- 15
- [1,2,3,4,5]
- 12345
Answer: 15. Rest parameters collect arguments into an array, and reduce sums them to 15.
With const greet = (name = 'Guest') => `Hello, ${name}!`, what does greet() return?
- Hello, !
- Hello, undefined!
- Hello, Guest!
- An error
Answer: Hello, Guest!. When no argument is passed, the default parameter 'Guest' is used.
What does undefined ?? 'Guest' evaluate to?
- undefined
- null
- Guest
- false
Answer: Guest. Nullish coalescing returns the right side when the left is null or undefined, so it returns 'Guest'.
How does ?? differ from || when defaulting?
- They are identical
- ?? only falls back for null/undefined, while || falls back for any falsy value
- || only falls back for null/undefined
- ?? falls back for any falsy value
Answer: ?? only falls back for null/undefined, while || falls back for any falsy value. The lesson notes ?? treats only null/undefined as empty, while || treats 0 and '' as falsy too.
Given const person = { name: 'Alice', age: 30 }, what does const { name: username } = person assign to username?
- 'Alice'
- 'username'
- 30
- undefined
Answer: 'Alice'. This renames the destructured name property to the variable username, which holds 'Alice'.
What does optional chaining like data?.user?.address?.city return if address is missing?
- null
- An error is thrown
- undefined
- An empty string
Answer: undefined. Optional chaining short-circuits and returns undefined safely when any link is missing.
Continue this course
- Previous: Arrays and Objects
- Next: Async/Await โ Write asynchronous code that's as readable as synchronous code
- Quick reference: JavaScript cheat sheet