ES6 was released in 2015 and completely transformed how JavaScript is written. Every modern codebase — React, Node, Vue, Next.js — uses these features constantly. Master them and your code will be cleaner, shorter, and more professional.
Day 18 / 180
Beginner Phase
🕐15 min read
💻8 code examples
🎯3 practice tasks
Look at these two pieces of code. Both do the exact same thing:
Old JS vs Modern ES6+
// ❌ Old JavaScript — ES5 (2009)var name = user.name || "Guest";
var city = user.address && user.address.city;
var msg = "Hello " + name + " from " + city + "!";
var arr2 = arr1.concat([4, 5]);
// ✅ Modern JavaScript — ES6+ (2015+)const name = user?.name ?? "Guest";
const city = user?.address?.city;
const msg = `Hello ${name} from ${city}!`;
const arr2 = [...arr1, 4, 5];
The modern version is shorter, safer, and far more readable. Every React codebase, every Node.js API, every professional JavaScript project uses these features on every single line. Today you learn all of them — in one complete lesson.
1. What is ES6+ — A Brief History
JavaScript gets updated every year by the TC39 committee. ES6 (ECMAScript 2015) was the biggest update in the language's history. Here are the most important versions and what they added:
Template literals use backticks instead of quotes and allow embedded expressions with ${}. They also support multi-line strings natively — no more \n:
ES6 — Template Literals
const name = "Waheed";
const age = 22;
const salary = 150000;
// ❌ Old way — string concatenationconst msg1 = "Hello, " + name + "! You are " + age + " years old.";
// ✅ Template literalconst msg2 = `Hello, ${name}! You are ${age} years old.`;
// Expressions inside ${}
console.log(`Salary after tax: Rs${salary * 0.9}`);
console.log(`Status: ${age >= 18 ? "Adult" : "Minor"}`);
// Multi-line stringsconst html = `
<div class="card">
<h2>${name}</h2>
<p>Age: ${age}</p>
<p>Salary: Rs${salary}</p>
</div>
`;
// Nested template literalsconst items = ["HTML", "CSS", "JS"];
const list = `Skills: ${items.join(" · ")}`;
console.log(list); // Skills: HTML · CSS · JS
3. Destructuring — Extract Values Cleanly
Destructuring lets you unpack values from arrays and objects into variables in one line. You have seen this before in Day 14 and 15 — but here is the complete picture with all patterns:
The three dots ... do two different things depending on where they are used. As spread they expand an array or object. As rest they collect remaining values. Same syntax — completely different behavior:
Optional chaining ?. was added in ES2020 and immediately became one of the most used operators. It safely accesses nested properties without crashing when something is null or undefined:
ES2020 — Optional Chaining
const user = {
name: "Waheed",
address: null,
getCity: null
};
// ❌ Without ?. — crashes!// console.log(user.address.city); // TypeError!// ✅ With ?. — returns undefined safely
console.log(user?.address?.city); // undefined
console.log(user?.social?.twitter); // undefined// ?. with arraysconst arr = null;
console.log(arr?.[0]); // undefined — no crash// ?. with function calls
console.log(user.getCity?.()); // undefined — no crash// Real world — API responseconst response = {
data: { users: [{ name: "Waheed" }] }
};
console.log(response?.data?.users?.[0]?.name); // "Waheed"
console.log(response?.data?.posts?.[0]?.title); // undefined// DOM — check element before usingconst el = document.querySelector("#maybe-missing");
el?.classList.add("active"); // safe — no crash if null
6. Nullish Coalescing ?? — Better Default Values
The ?? operator returns the right side only when the left side is null or undefined. This is a critical difference from || which also triggers on 0, "", and false:
ES2020 — Nullish Coalescing ??
// || returns fallback for ANY falsy value
console.log(0 || "default"); // "default" ← 0 is falsy! BUG
console.log("" || "default"); // "default" ← "" is falsy! BUG
console.log(false || "default"); // "default" ← false is falsy! BUG// ?? returns fallback ONLY for null/undefined
console.log(0 ?? "default"); // 0 ← correct ✅
console.log("" ?? "default"); // "" ← correct ✅
console.log(false ?? "default"); // false ← correct ✅
console.log(null ?? "default"); // "default" ← null triggers ✅// Real world — user settingsconst settings = { volume: 0, darkMode: false, username: "" };
// ❌ Wrong — || treats 0, false, "" as missingconst vol1 = settings.volume || 50; // 50 — WRONG! user set 0const dark1 = settings.darkMode || true; // true — WRONG! user set false// ✅ Correct — ?? only triggers on null/undefinedconst vol2 = settings.volume ?? 50; // 0 — correct ✅const dark2 = settings.darkMode ?? true; // false — correct ✅// Combine with ?.const city = user?.address?.city ?? "Unknown";
console.log(city); // "Unknown" if address is null
7. Logical Assignment & More Modern Features
ES2021 added logical assignment operators and several other small but powerful features that clean up common patterns significantly:
ES2021+ — Logical Assignment & Modern Features
// ── Logical Assignment Operators ──let a = null;
let b = "existing";
// ??= assign only if null/undefined
a ??= "default"; // a = "default" ← was null
b ??= "default"; // b = "existing" ← unchangedlet count = 0;
let name = "Waheed";
// ||= assign only if falsy
count ||= 10; // count = 10 ← was 0 (falsy)
name ||= "Guest"; // name = "Waheed" ← unchanged// &&= assign only if truthylet user = { name: "Waheed" };
user &&= { ...user, verified: true }; // updates if user exists// ── Array.at() — negative indexing ──const arr = [1, 2, 3, 4, 5];
console.log(arr.at(0)); // 1 ← first
console.log(arr.at(-1)); // 5 ← last
console.log(arr.at(-2)); // 4 ← second to last// ── String.replaceAll() ──const str = "cat and cat and cat";
console.log(str.replaceAll("cat", "dog"));
// "dog and dog and dog"// ── Object shorthand ──const city = "Faisalabad";
const age = 22;
// Old wayconst obj1 = { city: city, age: age };
// Shorthand — when key = variable nameconst obj2 = { city, age }; // ← same result!// ── Computed property keys ──const key = "name";
const obj3 = { [key]: "Waheed" };
console.log(obj3.name); // "Waheed"
Pro Tip #1 — Use ?? over || for defaults
Whenever you are providing a fallback for a value that might be missing — always prefer ?? over ||. The || operator treats 0, empty string, and false as "missing" which is almost never what you want in real applications with user data.
Pro Tip #2 — Chain ?. with ??
The combination user?.address?.city ?? "Unknown" is the gold standard for safely reading nested API data. Read it as: "get the city if it exists, otherwise return Unknown". You will write this pattern hundreds of times in React apps.
Pro Tip #3 — Object shorthand in React
Object shorthand { name, age } is used constantly in React — when passing props, creating state objects, and returning data from functions. When a variable name matches the key name you want — skip the repetition and use shorthand.
8. Try It Yourself
Edit the code and click Run Code. Try all the ES6+ features!
✏️ Try it Yourself — ES6+ Features
OUTPUT
// Click Run Code to see output
💡 Edit the code and click Run!
9. Practice Tasks
Task 1 — Easy: Profile Card Builder
Create a buildCard(user) function using destructuring in the parameters. Use template literals to build an HTML card string with name, city, salary, and skills. Use ?? for defaults and ?.skills?.join() safely. Return the HTML string.
Task 2 — Medium: Config Merger
Create a mergeConfig(defaults, userConfig) function. Use spread to merge objects. Use ??= to set any missing required fields to defaults. Use ?? for optional values. Handle nested objects safely with ?.. Return the final merged config object.
Task 3 — Hard: API Response Processor
Simulate an API response object with nested data — some properties may be null or undefined. Write a processUser(apiResponse) function that safely extracts: name (or "Anonymous"), email (or "Not provided"), city from nested address (or "Unknown"), first skill from skills array (or "No skills"), verified status (default false). Use ?., ??, destructuring, and template literals together. Log a formatted profile summary.