JavaScript ES6+ Essential Features
Master modern JavaScript features including arrow functions, destructuring, template literals, async/await, and more. Essential knowledge for every JavaScript developer.
What You'll Learn
Introduction to ES6+
ES6 (ECMAScript 2015) introduced many powerful features that revolutionized JavaScript development. These features make code more readable, concise, and maintainable. Let's explore the most important ones.
Arrow Functions
Arrow functions provide a more concise way to write functions and have different behavior with the this
keyword.
// Traditional function function add(a, b) { return a + b; } // Arrow function const add = (a, b) => a + b; // Multiple lines const multiply = (a, b) => { const result = a * b; return result; }; // Single parameter (parentheses optional) const square = x => x * x; // No parameters const greet = () => "Hello, World!"; // Array methods with arrow functions const numbers = [1, 2, 3, 4, 5]; const doubled = numbers.map(n => n * 2); const evens = numbers.filter(n => n % 2 === 0); const sum = numbers.reduce((acc, n) => acc + n, 0); console.log(doubled); // [2, 4, 6, 8, 10] console.log(evens); // [2, 4] console.log(sum); // 15
Lexical This
// Traditional function - 'this' changes context const obj = { name: 'Alice', hobbies: ['reading', 'coding'], // This won't work as expected showHobbies: function() { this.hobbies.forEach(function(hobby) { console.log(this.name + ' likes ' + hobby); // 'this' is undefined }); }, // Arrow function preserves 'this' showHobbiesArrow: function() { this.hobbies.forEach(hobby => { console.log(this.name + ' likes ' + hobby); // Works correctly }); } };
Template Literals
Template literals make string interpolation and multi-line strings much easier to work with.
// Old way const name = 'John'; const age = 30; const message = 'Hello, my name is ' + name + ' and I am ' + age + ' years old.'; // Template literals const message2 = `Hello, my name is ${name} and I am ${age} years old.`; // Multi-line strings const html = ` <div class="card"> <h2>${name}</h2> <p>Age: ${age}</p> </div> `; // Expressions in template literals const price = 19.99; const tax = 0.08; const total = `Total: $${(price * (1 + tax)).toFixed(2)}`;
Destructuring
Destructuring allows you to extract values from arrays and objects into distinct variables.
Array Destructuring
// Basic array destructuring const colors = ['red', 'green', 'blue']; const [first, second, third] = colors; console.log(first); // 'red' console.log(second); // 'green' console.log(third); // 'blue' // Skip elements const [primary, , tertiary] = colors; console.log(primary); // 'red' console.log(tertiary); // 'blue' // Default values const [a, b, c, d = 'yellow'] = colors; console.log(d); // 'yellow' // Rest operator const numbers = [1, 2, 3, 4, 5]; const [head, ...tail] = numbers; console.log(head); // 1 console.log(tail); // [2, 3, 4, 5] // Swapping variables let x = 1, y = 2; [x, y] = [y, x]; console.log(x, y); // 2, 1
Object Destructuring
// Basic object destructuring const person = { name: 'Alice', age: 30, city: 'New York', country: 'USA' }; const { name, age } = person; console.log(name); // 'Alice' console.log(age); // 30 // Renaming variables const { name: fullName, age: years } = person; console.log(fullName); // 'Alice' console.log(years); // 30 // Default values const { name, age, profession = 'Developer' } = person; console.log(profession); // 'Developer' // Function parameters function greetUser({ name, age = 25 }) { console.log(`Hello ${name}, you are ${age} years old`); } greetUser({ name: 'Charlie', age: 35 });
Spread and Rest Operators
The spread (...) operator allows you to expand arrays and objects, while the rest operator collects multiple elements.
// Spread with arrays const arr1 = [1, 2, 3]; const arr2 = [4, 5, 6]; const combined = [...arr1, ...arr2]; console.log(combined); // [1, 2, 3, 4, 5, 6] // Copy array const original = [1, 2, 3]; const copy = [...original]; // Spread with objects const obj1 = { a: 1, b: 2 }; const obj2 = { c: 3, d: 4 }; const merged = { ...obj1, ...obj2 }; console.log(merged); // { a: 1, b: 2, c: 3, d: 4 } // Function arguments function sum(...numbers) { return numbers.reduce((total, num) => total + num, 0); } console.log(sum(1, 2, 3, 4)); // 10
Promises and Async/Await
Modern JavaScript provides elegant ways to handle asynchronous operations.
// Creating a promise const fetchData = () => { return new Promise((resolve, reject) => { setTimeout(() => { const success = Math.random() > 0.5; if (success) { resolve({ data: 'Hello, World!' }); } else { reject(new Error('Failed to fetch data')); } }, 1000); }); }; // Using async/await async function getData() { try { const result = await fetchData(); console.log('Data received:', result.data); return result; } catch (error) { console.error('Error:', error.message); throw error; } } // Multiple async operations async function fetchMultipleData() { try { // Parallel execution const [result1, result2] = await Promise.all([ fetchData(), fetchData() ]); return { result1, result2 }; } catch (error) { console.error('Error in fetchMultipleData:', error); } }
Modules (Import/Export)
ES6 modules allow you to organize your code into separate files and import/export functionality.
// math.js - Named exports export const PI = 3.14159; export function add(a, b) { return a + b; } export function multiply(a, b) { return a * b; } // Default export export default function subtract(a, b) { return a - b; } // main.js - Importing import subtract, { add, multiply, PI } from './math.js'; console.log(add(5, 3)); // 8 console.log(subtract(10, 4)); // 6 console.log(PI); // 3.14159 // Import all import * as MathUtils from './math.js'; console.log(MathUtils.PI); // 3.14159
Enhanced Object Literals
const name = 'Alice'; const age = 30; // Shorthand property names const person = { name, age }; // Same as: { name: name, age: age } // Method definitions const calculator = { // Old way add: function(a, b) { return a + b; }, // New way subtract(a, b) { return a - b; } }; // Default function parameters function greet(name = 'World', greeting = 'Hello') { return `${greeting}, ${name}!`; } console.log(greet()); // "Hello, World!" console.log(greet('Alice')); // "Hello, Alice!" console.log(greet('Bob', 'Hi')); // "Hi, Bob!"
Practical Example: Task Manager
Let's combine these features in a practical example - a simple task manager using modern JavaScript.
class TaskManager { constructor(tasks = []) { this.tasks = tasks; } // Add task with default priority addTask(title, priority = 'medium') { const task = { id: Date.now(), title, priority, completed: false, createdAt: new Date() }; this.tasks = [...this.tasks, task]; return task; } // Get tasks by priority using destructuring getTasksByPriority(priority) { return this.tasks.filter(({ priority: taskPriority }) => taskPriority === priority ); } // Update task using spread operator updateTask(id, updates) { this.tasks = this.tasks.map(task => task.id === id ? { ...task, ...updates } : task ); } // Async method to save tasks async saveTasks() { try { const response = await fetch('/api/tasks', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(this.tasks) }); if (!response.ok) { throw new Error('Failed to save tasks'); } return await response.json(); } catch (error) { console.error('Save failed:', error); throw error; } } // Get task summary using template literals getSummary() { const total = this.tasks.length; const completed = this.tasks.filter(({ completed }) => completed).length; const pending = total - completed; return `Tasks: ${total} total, ${completed} completed, ${pending} pending`; } } // Usage example const taskManager = new TaskManager(); // Add tasks taskManager.addTask('Learn ES6', 'high'); taskManager.addTask('Build project', 'medium'); taskManager.addTask('Write tests'); // Get high priority tasks const highPriorityTasks = taskManager.getTasksByPriority('high'); console.log(highPriorityTasks); // Update task taskManager.updateTask(highPriorityTasks[0].id, { completed: true }); // Get summary console.log(taskManager.getSummary()); // Save tasks (async) taskManager.saveTasks() .then(() => console.log('Tasks saved successfully')) .catch(error => console.error('Failed to save:', error));
Next Steps
You've learned the essential ES6+ features that every modern JavaScript developer should know. Here are some areas to explore next:
- Advanced async patterns (generators, async iterators)
- Proxy and Reflect APIs
- WeakMap and WeakSet
- Symbol primitive type
- Optional chaining and nullish coalescing
- Dynamic imports and code splitting
💡 Practice Tip
Start using these features in your daily coding. Try refactoring old JavaScript code to use modern ES6+ syntax. The more you practice, the more natural these patterns will become.