JavaScript

Modern JavaScript ES6+ Features You Should Know

5 min read
#javascript#es6#programming#webdev

JavaScript has evolved significantly with ES6 (ES2015) and beyond. Let's explore the features that make modern JavaScript more powerful and elegant.

Arrow Functions

Concise syntax for writing functions:

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

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

// With single parameter
const square = x => x * x;

// With code block
const greet = name => {
    const message = `Hello, ${name}!`;
    return message;
};

Lexical this Binding

Arrow functions don't have their own this:

class Timer {
    constructor() {
        this.seconds = 0;
    }

    start() {
        setInterval(() => {
            this.seconds++; // 'this' refers to Timer instance
            console.log(this.seconds);
        }, 1000);
    }
}

Destructuring

Extract values from arrays and objects:

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

// Object destructuring
const user = {
    name: 'John',
    age: 30,
    email: 'john@example.com'
};

const { name, age } = user;
console.log(name);  // 'John'

// With renaming
const { name: userName, age: userAge } = user;

// Default values
const { country = 'USA' } = user;

Function Parameters

// Destructured parameters
function displayUser({ name, age, email }) {
    console.log(`${name} (${age}): ${email}`);
}

displayUser(user);

Template Literals

String interpolation and multi-line strings:

const name = 'Alice';
const age = 25;

// String interpolation
const greeting = `Hello, my name is ${name} and I'm ${age} years old.`;

// Multi-line strings
const html = `
    <div class="user">
        <h2>${name}</h2>
        <p>Age: ${age}</p>
    </div>
`;

// Expression evaluation
const price = 19.99;
const total = `Total: $${(price * 1.1).toFixed(2)}`;

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 person = { name: 'John', age: 30 };
const employee = { ...person, role: 'Developer' };

// Copy arrays/objects
const copy = [...arr1];
const clone = { ...person };

Rest Parameters

function sum(...numbers) {
    return numbers.reduce((total, num) => total + num, 0);
}

sum(1, 2, 3, 4, 5);  // 15

Enhanced Object Literals

const name = 'Alice';
const age = 25;

// Shorthand property names
const user = { name, age };

// Method shorthand
const calculator = {
    add(a, b) {
        return a + b;
    },
    subtract(a, b) {
        return a - b;
    }
};

// Computed property names
const key = 'email';
const person = {
    [key]: 'alice@example.com',
    [`${key}Verified`]: true
};

Promises and Async/Await

Promises

function fetchUser(id) {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            if (id > 0) {
                resolve({ id, name: 'John' });
            } else {
                reject(new Error('Invalid ID'));
            }
        }, 1000);
    });
}

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

Async/Await

async function getUser(id) {
    try {
        const user = await fetchUser(id);
        console.log(user);
        return user;
    } catch (error) {
        console.error('Error:', error);
    }
}

// Parallel execution
async function getAllUsers() {
    const [user1, user2, user3] = await Promise.all([
        fetchUser(1),
        fetchUser(2),
        fetchUser(3)
    ]);
    return [user1, user2, user3];
}

Classes

Syntactic sugar for prototypal inheritance:

class Person {
    constructor(name, age) {
        this.name = name;
        this.age = age;
    }

    introduce() {
        return `Hi, I'm ${this.name}`;
    }

    // Getter
    get birthYear() {
        return new Date().getFullYear() - this.age;
    }

    // Setter
    set fullName(value) {
        const [first, last] = value.split(' ');
        this.firstName = first;
        this.lastName = last;
    }

    // Static method
    static create(name, age) {
        return new Person(name, age);
    }
}

// Inheritance
class Developer extends Person {
    constructor(name, age, language) {
        super(name, age);
        this.language = language;
    }

    code() {
        return `${this.name} is coding in ${this.language}`;
    }
}

Modules

Exporting

// math.js
export const PI = 3.14159;

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

export default class Calculator {
    // ...
}

Importing

// app.js
import Calculator, { PI, add } from './math.js';

// Import everything
import * as math from './math.js';

// Rename imports
import { add as sum } from './math.js';

Array Methods

const numbers = [1, 2, 3, 4, 5];

// map
const doubled = numbers.map(n => n * 2);

// filter
const evens = numbers.filter(n => n % 2 === 0);

// reduce
const sum = numbers.reduce((acc, n) => acc + n, 0);

// find
const found = numbers.find(n => n > 3);

// some & every
const hasEven = numbers.some(n => n % 2 === 0);
const allPositive = numbers.every(n => n > 0);

Optional Chaining (?.)

Safely access nested properties:

const user = {
    name: 'John',
    address: {
        city: 'New York'
    }
};

// Without optional chaining
const zip = user && user.address && user.address.zip;

// With optional chaining
const zip = user?.address?.zip;

// With function calls
const result = obj?.someMethod?.(args);

Nullish Coalescing (??)

Provide default values for null/undefined:

const value = null ?? 'default';  // 'default'
const value = 0 ?? 'default';     // 0 (not default!)

// Compare with ||
const value = 0 || 'default';     // 'default'

Best Practices

  1. Use const by default, let when needed

    const PI = 3.14159;  // Won't change
    let counter = 0;      // Will change
    
  2. Prefer arrow functions for callbacks

    array.map(item => item * 2);
    
  3. Use destructuring for cleaner code

    const { name, age } = user;
    
  4. Async/await for better readability

    const data = await fetchData();
    
  5. Use template literals for string composition

    const message = `Hello, ${name}!`;
    

Conclusion

These ES6+ features make JavaScript more powerful, readable, and maintainable. Incorporate them into your daily coding to write modern, clean JavaScript.

Keep learning and exploring new features as JavaScript continues to evolve! 🚀