Modern JavaScript ES6+ Features - Complete Guide

Master modern JavaScript with ES6+ features including arrow functions, destructuring, async/await, modules, and advanced programming patterns.

Back to Articles

⚡ Arrow Functions and This Binding

Concise Function Syntax

// Traditional function
function add(a, b) {
    return a + b;
}

// Arrow function - concise syntax
const add = (a, b) => a + b;

// Multiple lines require braces
const processUser = (user) => {
    const processed = {
        ...user,
        fullName: `${user.firstName} ${user.lastName}`,
        timestamp: Date.now()
    };
    return processed;
};

// 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);

This Binding Differences

class Timer {
    constructor() {
        this.seconds = 0;
    }
    
    // Arrow function preserves 'this' context
    startWithArrow() {
        setInterval(() => {
            this.seconds++;
            console.log(this.seconds);
        }, 1000);
    }
    
    // Traditional function loses 'this' context
    startTraditional() {
        setInterval(function() {
            // this.seconds++; // TypeError: this is undefined
        }, 1000);
    }
}

📦 Destructuring Assignment

Array Destructuring

// Basic array destructuring
const colors = ['red', 'green', 'blue'];
const [primary, secondary, tertiary] = colors;

// Skipping elements
const [first, , third] = colors;

// Default values
const [a, b, c, d = 'yellow'] = colors;

// Rest operator
const [head, ...tail] = colors;
console.log(head); // 'red'
console.log(tail); // ['green', 'blue']

// Swapping variables
let x = 1, y = 2;
[x, y] = [y, x];

// Function returns
function getCoordinates() {
    return [10, 20];
}
const [x, y] = getCoordinates();

Object Destructuring

// Basic object destructuring
const user = {
    id: 1,
    name: 'John Doe',
    email: 'john@example.com',
    address: {
        city: 'New York',
        country: 'USA'
    }
};

const { name, email } = user;

// Renaming variables
const { name: userName, email: userEmail } = user;

// Default values
const { phone = 'Not provided' } = user;

// Nested destructuring
const { address: { city, country } } = user;

// Function parameters
function displayUser({ name, email, phone = 'N/A' }) {
    console.log(`${name} - ${email} - ${phone}`);
}

displayUser(user);

📜 Template Literals and String Methods

Template Literals

// Multi-line strings
const html = `
    

${user.name}

${user.email}

`; // Expression interpolation const price = 19.99; const tax = 0.08; const total = `Total: $${(price * (1 + tax)).toFixed(2)}`; // Tagged template literals function highlight(strings, ...values) { return strings.reduce((result, string, i) => { const value = values[i] ? `${values[i]}` : ''; return result + string + value; }, ''); } const name = 'JavaScript'; const version = 'ES6+'; const message = highlight`Learning ${name} ${version} features!`;

New String Methods

const text = "JavaScript Programming";

// String checking methods
console.log(text.startsWith('Java')); // true
console.log(text.endsWith('ing')); // true
console.log(text.includes('Script')); // true

// String repetition
console.log('*'.repeat(10)); // '**********'

// Padding
console.log('5'.padStart(3, '0')); // '005'
console.log('5'.padEnd(3, '0')); // '500'

// String trimming (ES2019)
const spaced = '  hello world  ';
console.log(spaced.trimStart()); // 'hello world  '
console.log(spaced.trimEnd()); // '  hello world'

🔄 Spread and Rest Operators

Spread Operator (...)

// Array spreading
const arr1 = [1, 2, 3];
const arr2 = [4, 5, 6];
const combined = [...arr1, ...arr2]; // [1, 2, 3, 4, 5, 6]

// Object spreading
const defaults = { theme: 'dark', lang: 'en' };
const userPrefs = { theme: 'light', fontSize: 14 };
const settings = { ...defaults, ...userPrefs }; // { theme: 'light', lang: 'en', fontSize: 14 }

// Function arguments
function sum(a, b, c) {
    return a + b + c;
}
const numbers = [1, 2, 3];
console.log(sum(...numbers)); // 6

// Copying arrays/objects (shallow copy)
const originalArray = [1, 2, 3];
const copiedArray = [...originalArray];
const originalObject = { a: 1, b: 2 };
const copiedObject = { ...originalObject };

Rest Operator (...)

// Function parameters
function multiply(multiplier, ...numbers) {
    return numbers.map(n => n * multiplier);
}
console.log(multiply(2, 1, 2, 3, 4)); // [2, 4, 6, 8]

// Destructuring with rest
const [first, second, ...remaining] = [1, 2, 3, 4, 5];
console.log(remaining); // [3, 4, 5]

const { name, ...otherProps } = user;
console.log(otherProps); // All properties except 'name'

🔮 Promises and Async/Await

Promises

// Creating a Promise
function fetchUser(id) {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            if (id > 0) {
                resolve({ id, name: `User ${id}` });
            } else {
                reject(new Error('Invalid user ID'));
            }
        }, 1000);
    });
}

// Using Promises
fetchUser(1)
    .then(user => console.log(user))
    .catch(error => console.error(error));

// Promise chaining
fetchUser(1)
    .then(user => {
        console.log('User fetched:', user);
        return fetch(`/api/posts/${user.id}`);
    })
    .then(response => response.json())
    .then(posts => console.log('Posts:', posts))
    .catch(error => console.error('Error:', error));

Async/Await

// Async function declaration
async function getUserData(id) {
    try {
        const user = await fetchUser(id);
        const posts = await fetch(`/api/posts/${user.id}`);
        const postsData = await posts.json();
        
        return {
            user,
            posts: postsData
        };
    } catch (error) {
        console.error('Error fetching user data:', error);
        throw error;
    }
}

// Using async/await
async function displayUserInfo() {
    try {
        const userData = await getUserData(1);
        console.log('User:', userData.user);
        console.log('Posts:', userData.posts);
    } catch (error) {
        console.error('Failed to display user info:', error);
    }
}

// Parallel execution
async function fetchMultipleUsers() {
    try {
        const users = await Promise.all([
            fetchUser(1),
            fetchUser(2),
            fetchUser(3)
        ]);
        console.log('All users:', users);
    } catch (error) {
        console.error('One or more requests failed:', error);
    }
}

📦 Modules (Import/Export)

Named Exports and Imports

// utils.js - Named exports
export const PI = 3.14159;

export function calculateArea(radius) {
    return PI * radius * radius;
}

export class Calculator {
    add(a, b) { return a + b; }
    subtract(a, b) { return a - b; }
}

// main.js - Named imports
import { PI, calculateArea, Calculator } from './utils.js';

// Renaming imports
import { calculateArea as getCircleArea } from './utils.js';

// Import all
import * as Utils from './utils.js';
console.log(Utils.PI);

Default Exports

// logger.js - Default export
export default class Logger {
    log(message) {
        console.log(`[${new Date().toISOString()}] ${message}`);
    }
    
    error(message) {
        console.error(`[${new Date().toISOString()}] ERROR: ${message}`);
    }
}

// main.js - Default import
import Logger from './logger.js';

const logger = new Logger();
logger.log('Application started');

// Mixed exports/imports
// api.js
export const BASE_URL = 'https://api.example.com';
export default class ApiClient {
    async get(endpoint) {
        return fetch(`${BASE_URL}/${endpoint}`);
    }
}

// main.js
import ApiClient, { BASE_URL } from './api.js';

🏗️ Classes and Inheritance

Class Declaration

class Animal {
    constructor(name, species) {
        this.name = name;
        this.species = species;
    }
    
    // Instance method
    speak() {
        return `${this.name} makes a sound`;
    }
    
    // Getter
    get info() {
        return `${this.name} is a ${this.species}`;
    }
    
    // Setter
    set name(newName) {
        if (newName.length > 0) {
            this._name = newName;
        }
    }
    
    get name() {
        return this._name;
    }
    
    // Static method
    static compareAnimals(animal1, animal2) {
        return animal1.species === animal2.species;
    }
}

const dog = new Animal('Buddy', 'Dog');
console.log(dog.speak()); // "Buddy makes a sound"
console.log(dog.info); // "Buddy is a Dog"

Class Inheritance

class Dog extends Animal {
    constructor(name, breed) {
        super(name, 'Dog'); // Call parent constructor
        this.breed = breed;
    }
    
    // Override parent method
    speak() {
        return `${this.name} barks`;
    }
    
    // New method specific to Dog
    fetch() {
        return `${this.name} fetches the ball`;
    }
    
    // Override getter
    get info() {
        return `${super.info} of breed ${this.breed}`;
    }
}

class Cat extends Animal {
    constructor(name, indoor = true) {
        super(name, 'Cat');
        this.indoor = indoor;
    }
    
    speak() {
        return `${this.name} meows`;
    }
    
    hunt() {
        return this.indoor ? 
            `${this.name} hunts toy mice` : 
            `${this.name} hunts real mice`;
    }
}

const myDog = new Dog('Rex', 'Golden Retriever');
const myCat = new Cat('Whiskers', false);

console.log(myDog.speak()); // "Rex barks"
console.log(myDog.fetch()); // "Rex fetches the ball"
console.log(myCat.hunt()); // "Whiskers hunts real mice"

🧰 Advanced Array Methods

Powerful Array Operations

const users = [
    { id: 1, name: 'Alice', age: 25, active: true },
    { id: 2, name: 'Bob', age: 30, active: false },
    { id: 3, name: 'Charlie', age: 35, active: true },
    { id: 4, name: 'Diana', age: 28, active: true }
];

// Find methods
const activeUser = users.find(user => user.active);
const userIndex = users.findIndex(user => user.name === 'Bob');

// Check methods
const allActive = users.every(user => user.active); // false
const someActive = users.some(user => user.active); // true

// includes for primitive arrays
const numbers = [1, 2, 3, 4, 5];
console.log(numbers.includes(3)); // true

// Advanced filtering and mapping
const activeUserNames = users
    .filter(user => user.active)
    .map(user => user.name);

// Reduce for complex operations
const totalAge = users.reduce((sum, user) => sum + user.age, 0);
const usersByAge = users.reduce((acc, user) => {
    acc[user.age] = user;
    return acc;
}, {});

// Chaining operations
const result = users
    .filter(user => user.active)
    .map(user => ({ ...user, category: user.age > 30 ? 'senior' : 'junior' }))
    .sort((a, b) => a.age - b.age);

Newer Array Methods (ES2019+)

// Array.flat() - flattens nested arrays
const nested = [[1, 2], [3, 4], [5, [6, 7]]];
console.log(nested.flat()); // [1, 2, 3, 4, 5, [6, 7]]
console.log(nested.flat(2)); // [1, 2, 3, 4, 5, 6, 7]

// Array.flatMap() - map then flat
const words = ['Hello World', 'JavaScript Rules'];
const allWords = words.flatMap(phrase => phrase.split(' '));
// ['Hello', 'World', 'JavaScript', 'Rules']

// Array.from() with mapping
const range = Array.from({ length: 5 }, (_, i) => i + 1);
// [1, 2, 3, 4, 5]

const doubled = Array.from(numbers, x => x * 2);
// [2, 4, 6, 8, 10]

🔧 Modern JavaScript Best Practices

Error Handling

// Custom Error classes
class ValidationError extends Error {
    constructor(message, field) {
        super(message);
        this.name = 'ValidationError';
        this.field = field;
    }
}

class NetworkError extends Error {
    constructor(message, status) {
        super(message);
        this.name = 'NetworkError';
        this.status = status;
    }
}

// Async error handling
async function fetchUserData(id) {
    try {
        if (!id) {
            throw new ValidationError('User ID is required', 'id');
        }
        
        const response = await fetch(`/api/users/${id}`);
        
        if (!response.ok) {
            throw new NetworkError(
                `Failed to fetch user: ${response.statusText}`,
                response.status
            );
        }
        
        return await response.json();
    } catch (error) {
        if (error instanceof ValidationError) {
            console.error(`Validation error in field ${error.field}: ${error.message}`);
        } else if (error instanceof NetworkError) {
            console.error(`Network error (${error.status}): ${error.message}`);
        } else {
            console.error('Unexpected error:', error);
        }
        throw error; // Re-throw for caller to handle
    }
}

Performance Optimization

// Debouncing
function debounce(func, delay) {
    let timeoutId;
    return function (...args) {
        clearTimeout(timeoutId);
        timeoutId = setTimeout(() => func.apply(this, args), delay);
    };
}

// Throttling
function throttle(func, limit) {
    let inThrottle;
    return function (...args) {
        if (!inThrottle) {
            func.apply(this, args);
            inThrottle = true;
            setTimeout(() => inThrottle = false, limit);
        }
    };
}

// Memoization
function memoize(fn) {
    const cache = new Map();
    return function (...args) {
        const key = JSON.stringify(args);
        if (cache.has(key)) {
            return cache.get(key);
        }
        const result = fn.apply(this, args);
        cache.set(key, result);
        return result;
    };
}

// Usage examples
const debouncedSearch = debounce(searchFunction, 300);
const throttledScroll = throttle(scrollHandler, 100);
const memoizedCalculation = memoize(expensiveFunction);

🎯 Conclusion

Modern JavaScript ES6+ features provide powerful tools for writing cleaner, more efficient, and maintainable code. These features are now standard in modern web development and are essential for any JavaScript developer.

Practice these concepts regularly, and gradually incorporate them into your projects. The combination of these features enables you to write code that is both powerful and readable.

🚀 Next Steps

  • Practice with ES6+ features in small projects
  • Learn about newer features in ES2020, ES2021, and beyond
  • Explore TypeScript for type-safe JavaScript development
  • Study advanced asynchronous patterns and Web APIs
  • Build projects using modern JavaScript frameworks