Advanced JavaScript

Master advanced JavaScript concepts including design patterns, performance optimization, and modern development practices.

advanced JavaScript 7 hours

Chapter 5: Design Patterns in JavaScript

Chapter 5 of 15

Chapter 5: Design Patterns in JavaScript

5.1 Creational Patterns

Creational patterns provide mechanisms for object creation that increase flexibility and reuse of existing code.

Singleton Pattern:

// Ensures only one instance exists
const Singleton = (function() {
    let instance;
    
    function createInstance() {
        return {
            data: 'Shared data',
            getData: function() {
                return this.data;
            }
        };
    }
    
    return {
        getInstance: function() {
            if (!instance) {
                instance = createInstance();
            }
            return instance;
        }
    };
})();

const instance1 = Singleton.getInstance();
const instance2 = Singleton.getInstance();
console.log(instance1 === instance2); // true - same instance

Factory Pattern:

// Creates objects without specifying exact class
function createUser(type, name) {
    if (type === 'admin') {
        return {
            name: name,
            role: 'admin',
            permissions: ['read', 'write', 'delete']
        };
    } else if (type === 'user') {
        return {
            name: name,
            role: 'user',
            permissions: ['read']
        };
    }
    throw new Error('Invalid user type');
}

const admin = createUser('admin', 'John');
const user = createUser('user', 'Jane');

Builder Pattern:

class QueryBuilder {
    constructor() {
        this.query = {
            select: [],
            from: "",
            where: [],
            orderBy: []
        };
    }
    
    select(fields) {
        this.query.select = fields;
        return this;
    }
    
    from(table) {
        this.query.from = table;
        return this;
    }
    
    where(condition) {
        this.query.where.push(condition);
        return this;
    }
    
    orderBy(field, direction = 'ASC') {
        this.query.orderBy.push({ field, direction });
        return this;
    }
    
    build() {
        return this.query;
    }
}

const query = new QueryBuilder()
    .select(['id', 'name', 'email'])
    .from('users')
    .where('status = active')
    .orderBy('name', 'ASC')
    .build();

5.2 Structural Patterns

Structural patterns explain how to assemble objects and classes into larger structures while keeping them flexible and efficient.

Module Pattern:

const MyModule = (function() {
    // Private variables and functions
    let privateVar = 0;
    
    function privateFunction() {
        return 'Private';
    }
    
    // Public API
    return {
        publicMethod: function() {
            privateVar++;
            return privateFunction() + ' - ' + privateVar;
        },
        getPrivateVar: function() {
            return privateVar;
        }
    };
})();

console.log(MyModule.publicMethod()); // "Private - 1"
// privateVar and privateFunction are not accessible

Observer Pattern:

class EventEmitter {
    constructor() {
        this.events = {};
    }
    
    on(event, callback) {
        if (!this.events[event]) {
            this.events[event] = [];
        }
        this.events[event].push(callback);
    }
    
    emit(event, data) {
        if (this.events[event]) {
            this.events[event].forEach(callback => callback(data));
        }
    }
    
    off(event, callback) {
        if (this.events[event]) {
            this.events[event] = this.events[event].filter(cb => cb !== callback);
        }
    }
}

const emitter = new EventEmitter();
emitter.on('userLogin', (user) => {
    console.log(`User ${user.name} logged in`);
});
emitter.emit('userLogin', { name: 'John' });

5.3 Behavioral Patterns

Behavioral patterns are concerned with algorithms and the assignment of responsibilities between objects.

Strategy Pattern:

// Encapsulates algorithms and makes them interchangeable
const paymentStrategies = {
    creditCard: function(amount) {
        return `Paid $${amount} via Credit Card`;
    },
    paypal: function(amount) {
        return `Paid $${amount} via PayPal`;
    },
    crypto: function(amount) {
        return `Paid $${amount} via Cryptocurrency`;
    }
};

function PaymentProcessor(strategy) {
    this.strategy = strategy;
    this.pay = function(amount) {
        return paymentStrategies[this.strategy](amount);
    };
}

const payment = new PaymentProcessor('paypal');
console.log(payment.pay(100)); // "Paid $100 via PayPal"

5.4 MVC Pattern

// Model - Data and business logic
class Model {
    constructor() {
        this.data = [];
    }
    
    add(item) {
        this.data.push(item);
        this.notify();
    }
    
    notify() {
        // Notify view of changes
    }
}

// View - Presentation layer
class View {
    render(data) {
        console.log('Rendering:', data);
    }
}

// Controller - Mediates between Model and View
class Controller {
    constructor(model, view) {
        this.model = model;
        this.view = view;
    }
    
    addItem(item) {
        this.model.add(item);
        this.view.render(this.model.data);
    }
}