JavaScript Advanced Concepts 
                CMU422: Fundamentals of Web Design - Session 8 
                Birmingham Newman University 
                Lecturer: James Williams 
                Functions, objects, and modern JavaScript
                3-hour session • 26 slides • 2 interactive tasks 
                
                    Session Timeline: 
                    
                        10 min: Registration & waiting 
                        20 min: Opening slides 
                        45 min: Task 1 
                        15 min: Break/Catch up 
                        20 min: Secondary slides 
                        45 min: Task 2 
                        Remaining: Self-study 
                     
                 
             
            
            
                Learning Objectives 
                
                    Master advanced function concepts 
                    Understand object-oriented programming 
                    Learn modern JavaScript features 
                    Work with asynchronous programming 
                    Apply functional programming concepts 
                 
             
            
            
                Advanced Function Concepts 
                
                    Functions  are first-class citizens in JavaScript
                
                
                    // Function declaration 
                    function greet(name) { return `Hello ${name}`; } 
                    // Function expression 
                    const greet = function(name) { return `Hello ${name}`; }; 
                    // Arrow function 
                    const greet = (name) => `Hello ${name}`; 
                    // Immediately Invoked Function Expression (IIFE) 
                    (function() { console.log('IIFE'); })();
                
                
                    Multiple ways to define functions 
                    Functions can be assigned to variables 
                    Functions can be passed as arguments 
                    Functions can return other functions 
                 
             
            
            
                Higher-Order Functions 
                
                    // Function that returns a function 
                    function multiply(x) { 
                      return function(y) { 
                        return x * y; 
                      }; 
                    } 
                    const multiplyByTwo = multiply(2); 
                    console.log(multiplyByTwo(5)); // 10 
                    // Function that takes a function as argument 
                    function processArray(arr, callback) { 
                      return arr.map(callback); 
                    } 
                    const numbers = [1, 2, 3, 4]; 
                    const doubled = processArray(numbers, x => x * 2);
                
                
                    Functions that return functions 
                    Functions that take functions as arguments 
                    Enable functional programming patterns 
                    Create reusable and composable code 
                 
                
                
                    Try It: Advanced JavaScript Concepts 
                    
                        
                            
                                Closures 
                                Promises 
                                Async/Await 
                            
                            
                                
                                    Closure Demo 
                                    
                                        Create
                                            Counter 
                                        Increment 
                                        Create
                                            Wallet 
                                        Deposit
                                            $10 
                                        Withdraw $5 
                                    
                                    
                                        Click buttons to see closures in
                                            action!
                                     
                                 
                                
                                    Promise Demo 
                                    
                                        Start Async Task 
                                        Promise Chain 
                                        Promise.all() 
                                    
                                    
                                        Click buttons to see promises in
                                            action!
                                     
                                 
                                
                                    Async/Await Demo 
                                    
                                        Async
                                            Function 
                                        Error Handling 
                                        Parallel
                                            Execution 
                                    
                                    
                                        Click buttons to see async/await
                                            in action!
                                     
                                 
                             
                            
                                Current Concept: 
                                Closures allow functions to access
                                    variables from their outer scope even after the outer function
                                    has returned.
                             
                         
                     
                    
                        Explore advanced JavaScript concepts with interactive examples!
                    
                 
             
            
            
                Closures 
                
                    function createCounter() { 
                      let count = 0; 
                      return function() { 
                        count++; 
                        return count; 
                      }; 
                    } 
                    const counter = createCounter(); 
                    console.log(counter()); // 1 
                    console.log(counter()); // 2 
                    console.log(counter()); // 3 
                    // Private variables 
                    function createWallet(initialBalance) { 
                      let balance = initialBalance; 
                      return { 
                        getBalance: () => balance, 
                        deposit: (amount) => { balance += amount; }, 
                        withdraw: (amount) => { 
                          if (amount <= balance) { 
                                balance -= amount; 
                                return true; 
                              } 
                              return false; 
                            } 
                          }; 
                        }
                
                
                    Functions that remember their lexical scope 
                    Access to variables from outer scope 
                    Used for data privacy and state management 
                    Common in modern JavaScript patterns 
                 
             
            
            
                Object-Oriented Programming 
                
                    // Constructor function 
                    function Person(name, age) { 
                      this.name = name; 
                      this.age = age; 
                    } 
                    Person.prototype.greet = function() { 
                      return `Hello, I'm ${this.name}`; 
                    }; 
                    const person = new Person('John', 30); 
                    console.log(person.greet()); // "Hello, I'm John" 
                    // ES6 Classes 
                    class Person { 
                      constructor(name, age) { 
                        this.name = name; 
                        this.age = age; 
                      } 
                      greet() { 
                        return `Hello, I'm ${this.name}`; 
                      } 
                    }
                
                
                    Constructor functions and prototypes 
                    ES6 class syntax (syntactic sugar) 
                    Inheritance and polymorphism 
                    Encapsulation and abstraction 
                 
             
            
            
                Inheritance 
                
                    class Animal { 
                      constructor(name) { 
                        this.name = name; 
                      } 
                      speak() { 
                        return `${this.name} makes a sound`; 
                      } 
                    } 
                    class Dog extends Animal { 
                      constructor(name, breed) { 
                        super(name); 
                        this.breed = breed; 
                      } 
                      speak() { 
                        return `${this.name} barks`; 
                      } 
                      fetch() { 
                        return `${this.name} fetches the ball`; 
                      } 
                    } 
                    const dog = new Dog('Buddy', 'Golden Retriever'); 
                    console.log(dog.speak()); // "Buddy barks"
                
                
                    Use extends for inheritance 
                    Call super() in constructor 
                    Override methods in child classes 
                    Add new methods to child classes 
                 
             
            
            
                Modern JavaScript Features 
                
                    // Destructuring 
                    const { name, age } = person; 
                    const [first, second, ...rest] = array; 
                    // Spread operator 
                    const newArray = [...oldArray, newItem]; 
                    const newObject = { ...oldObject, newProperty: value }; 
                    // Template literals 
                    const message = `Hello ${name}, you are ${age} years old`; 
                    // Default parameters 
                    function greet(name = 'Guest') { 
                      return `Hello ${name}`; 
                    } 
                    // Rest parameters 
                    function sum(...numbers) { 
                      return numbers.reduce((a, b) => a + b, 0); 
                    }
                
                
                    Destructuring for cleaner code 
                    Spread operator for copying and merging 
                    Template literals for string interpolation 
                    Default and rest parameters 
                 
             
            
            
                Promises 
                
                    // Creating a promise 
                    const myPromise = new Promise((resolve, reject) => { 
                      setTimeout(() => { 
                        const random = Math.random(); 
                        if (random > 0.5) { 
                          resolve('Success!'); 
                        } else { 
                          reject('Failed!'); 
                        } 
                      }, 1000); 
                    }); 
                    // Using promises 
                    myPromise 
                      .then(result => console.log(result)) 
                      .catch(error => console.error(error)); 
                    // Promise chaining 
                    fetch('/api/data') 
                      .then(response => response.json()) 
                      .then(data => processData(data)) 
                      .catch(error => handleError(error));
                
                
                    Handle asynchronous operations 
                    Better than callbacks 
                    Chain multiple operations 
                    Error handling with catch 
                 
             
            
            
                Async/Await 
                
                    // Async function 
                    async function fetchUserData(userId) { 
                      try { 
                        const response = await
                    fetch(`/api/users/${userId}`); 
                        if (!response.ok) { 
                          throw new Error('User not found'); 
                        } 
                        const userData = await response.json(); 
                        return userData; 
                      } catch (error) { 
                        console.error('Error fetching user:', error); 
                        throw error; 
                      } 
                    } 
                    // Using async function 
                    async function displayUser(userId) { 
                      const user = await fetchUserData(userId); 
                      console.log(`User: ${user.name}`); 
                    } 
                    // Arrow function with async 
                    const loadData = async () => { 
                      const data = await fetch('/api/data'); 
                      return data.json(); 
                    };
                
                
                    Syntactic sugar over promises 
                    Makes async code look synchronous 
                    Better error handling with try/catch 
                    Easier to read and understand 
                 
             
            
            
                ES6 Modules 
                
                    // math.js (exporting) 
                    export const add = (a, b) => a + b; 
                    export const subtract = (a, b) => a - b; 
                    export default class Calculator { 
                      multiply(a, b) { return a * b; } 
                    } 
                    // app.js (importing) 
                    import Calculator, { add, subtract } from './math.js'; 
                    const calc = new Calculator(); 
                    console.log(add(5, 3)); // 8 
                    console.log(calc.multiply(4, 2)); // 8 
                    // Dynamic imports 
                    const module = await import('./dynamic-module.js');
                
                
                    Organize code into separate files 
                    Export and import functionality 
                    Default and named exports 
                    Dynamic imports for code splitting 
                 
             
            
            
                Functional Programming Concepts 
                
                    // Pure functions 
                    const add = (a, b) => a + b; 
                    const multiply = (a, b) => a * b; 
                    // Function composition 
                    const compose = (...fns) => x => 
                      fns.reduceRight((acc, fn) => fn(acc), x); 
                    const addOne = x => x + 1; 
                    const double = x => x * 2; 
                    const addOneAndDouble = compose(double, addOne); 
                    console.log(addOneAndDouble(5)); // 12 
                    // Immutability 
                    const original = [1, 2, 3]; 
                    const doubled = original.map(x => x * 2); 
                    // original is unchanged
                
                
                    Pure functions (no side effects) 
                    Function composition 
                    Immutability 
                    Higher-order functions 
                 
             
            
            
                Modern Array Methods 
                
                    const numbers = [1, 2, 3, 4, 5]; 
                    // Map 
                    const doubled = numbers.map(x => x * 2); 
                    // [2, 4, 6, 8, 10] 
                    // Filter 
                    const evens = numbers.filter(x => x % 2 === 0); 
                    // [2, 4] 
                    // Reduce 
                    const sum = numbers.reduce((acc, x) => acc + x, 0); 
                    // 15 
                    // Find 
                    const firstEven = numbers.find(x => x % 2 === 0); 
                    // 2 
                    // Some 
                    const hasEven = numbers.some(x => x % 2 === 0); 
                    // true 
                    // Every 
                    const allPositive = numbers.every(x => x > 0); 
                    // true
                
                
                    Functional programming approach 
                    Chain multiple operations 
                    More readable than loops 
                    Immutable operations 
                 
             
            
            
                Advanced Error Handling 
                
                    // Custom error classes 
                    class ValidationError extends Error { 
                      constructor(message, field) { 
                        super(message); 
                        this.name = 'ValidationError'; 
                        this.field = field; 
                      } 
                    } 
                    // Error handling with async/await 
                    async function processData(data) { 
                      try { 
                        if (!data) { 
                          throw new ValidationError('Data is
                    required', 'data'); 
                        } 
                        const result = await validateAndProcess(data); 
                        return result; 
                      } catch (error) { 
                        if (error instanceof ValidationError) { 
                          console.error(`Validation error in
                    ${error.field}:`, error.message); 
                        } else { 
                          console.error('Unexpected error:',
                    error); 
                        } 
                        throw error; 
                      } 
                    }
                
                
                    Custom error classes 
                    Error inheritance 
                    Type checking with instanceof 
                    Proper error propagation 
                 
             
            
            
                Performance Optimization 
                
                    Memoization for expensive calculations 
                    Debouncing and throttling 
                    Lazy loading and code splitting 
                    Efficient DOM manipulation 
                    Memory leak prevention 
                 
                
                    // 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; 
                      }; 
                    } 
                    // Debouncing 
                    function debounce(func, wait) { 
                      let timeout; 
                      return function executedFunction(...args) { 
                        const later = () => { 
                          clearTimeout(timeout); 
                          func(...args); 
                        }; 
                        clearTimeout(timeout); 
                        timeout = setTimeout(later, wait); 
                      }; 
                    }
                
             
            
            
                Testing JavaScript Code 
                
                    Unit testing with Jest or Mocha 
                    Test-driven development (TDD) 
                    Mocking and stubbing 
                    Integration testing 
                    Code coverage 
                 
                
                    // Example test with Jest 
                    function add(a, b) { 
                      return a + b; 
                    } 
                    // test.js 
                    describe('add function', () => { 
                      test('adds two positive numbers', () => { 
                        expect(add(2, 3)).toBe(5); 
                      }); 
                      test('adds negative numbers', () => { 
                        expect(add(-1, -2)).toBe(-3); 
                      }); 
                      test('handles zero', () => { 
                        expect(add(0, 5)).toBe(5); 
                      }); 
                    });
                
             
            
            
                Advanced Debugging 
                
                    Browser developer tools 
                    Console methods (log, warn, error, table) 
                    Breakpoints and step-through 
                    Performance profiling 
                    Memory leak detection 
                 
                
                    // Debugging techniques 
                    console.log('Debug info:', { user, data }); 
                    console.table(arrayOfObjects); 
                    console.trace('Function call stack'); 
                    // Performance measurement 
                    console.time('operation'); 
                    // ... expensive operation 
                    console.timeEnd('operation'); 
                    // Debugger statement 
                    function complexFunction() { 
                      let result = 0; 
                      debugger; // Execution stops here 
                      return result; 
                    }
                
             
            
            
                Task 1: Advanced JavaScript Library 
                
                    Instructions: 
                    
                        Create a new JavaScript file called advanced-library.js
                         
                        Build a utility library with: 
                        
                            Math utilities:  Advanced mathematical functions
                             
                            Array utilities:  Custom array manipulation methods
                             
                            Object utilities:  Deep cloning, merging, validation
                             
                            Async utilities:  Promise helpers and async
                                operations 
                         
                        Use modern JavaScript features: 
                        
                            ES6 classes and modules 
                            Arrow functions and destructuring 
                            Promises and async/await 
                            Higher-order functions 
                         
                        Implement proper error handling 
                        Add JSDoc documentation 
                        Create unit tests for your functions 
                     
                    Time:  45 minutes
                    This task will help you understand advanced JavaScript concepts and
                            patterns 
                 
             
            
            
                Break Time 
                
                    15 Minutes 
                    Take a break, ask questions, or catch up on the previous task.
                    Next: Secondary slides and Task 2 
                 
             
            
            
                Common Design Patterns 
                
                    Singleton:  Single instance pattern 
                    Factory:  Object creation pattern 
                    Observer:  Event handling pattern 
                    Module:  Encapsulation pattern 
                    Decorator:  Function enhancement pattern 
                 
                
                    // Singleton pattern 
                    class Database { 
                      constructor() { 
                        if (Database.instance) { 
                          return Database.instance; 
                        } 
                        Database.instance = this; 
                      } 
                    } 
                    // Factory pattern 
                    class UserFactory { 
                      createUser(type, data) { 
                        switch(type) { 
                          case 'admin': return new
                    AdminUser(data); 
                          case 'regular': return new
                    RegularUser(data); 
                        } 
                      } 
                    }
                
             
            
            
                Memory Management 
                
                    Garbage collection 
                    Memory leaks prevention 
                    Event listener cleanup 
                    Closure memory considerations 
                    WeakMap and WeakSet usage 
                 
                
                    // Memory leak prevention 
                    class EventManager { 
                      constructor() { 
                        this.listeners = new Map(); 
                      } 
                      addListener(element, event, handler) { 
                        element.addEventListener(event, handler); 
                        this.listeners.set(element, { event, handler }); 
                      } 
                      removeListener(element) { 
                        const listener = this.listeners.get(element); 
                        if (listener) { 
                          element.removeEventListener(listener.event,
                    listener.handler); 
                          this.listeners.delete(element); 
                        } 
                      } 
                      cleanup() { 
                        this.listeners.forEach((listener, element) => { 
                          this.removeListener(element); 
                        }); 
                      } 
                    }
                
             
            
            
                Security Best Practices 
                
                    Input validation and sanitization 
                    XSS prevention 
                    CSRF protection 
                    Secure coding practices 
                    Content Security Policy (CSP) 
                 
                
                    // Input validation 
                    function validateInput(input) { 
                      if (typeof input !== 'string') { 
                        throw new Error('Input must be a string'); 
                      } 
                      return input.replace(/[<>]/g, ''); // Basic XSS prevention 
                        } 
                        // Secure object property access 
                        const safeGet = (obj, path) => { 
                          return path.split('.').reduce((current, key) => { 
                            return current && current[key] !== undefined ?
                        current[key] : null; 
                          }, obj); 
                        };
                
             
            
            
                Code Quality and Standards 
                
                    ESLint for code linting 
                    Prettier for code formatting 
                    JSDoc for documentation 
                    TypeScript for type safety 
                    Code review practices 
                 
                
                    // JSDoc documentation 
                    /** 
                    * Calculates the factorial of a number 
                    * @param {number} n - The number to calculate factorial for 
                    * @returns {number} The factorial of n 
                    * @throws {Error} If n is negative 
                    */ 
                    function factorial(n) { 
                      if (n < 0) { 
                            throw new Error('Factorial is not defined for
                        negative numbers'); 
                          } 
                          if (n === 0 || n === 1) { 
                            return 1; 
                          } 
                          return n * factorial(n - 1); 
                        }
                
             
            
            
                Task 2: Complete Web Application 
                
                    Instructions: 
                    
                        Create a complete web application using all concepts learned 
                        Build a task management app with: 
                        
                            Architecture:  Modular design with ES6 modules 
                            Data Management:  Local storage with CRUD operations
                             
                            UI Components:  Reusable components using classes
                             
                            Async Operations:  Simulated API calls with promises
                             
                            Event Handling:  Advanced event delegation and
                                custom events 
                         
                        Implement advanced features: 
                        
                            Task filtering and sorting 
                            Drag and drop functionality 
                            Real-time search with debouncing 
                            Data validation and error handling 
                            Responsive design with modern CSS 
                         
                        Use design patterns (Factory, Observer, Module) 
                        Add comprehensive error handling and logging 
                        Include unit tests for core functionality 
                     
                    Time:  45 minutes
                    This task will help you understand full-stack JavaScript development 
                    
                 
             
            
            
                Common Advanced Issues 
                
                    Scope issues:  Check closure and context 
                    Async problems:  Promise rejection handling 
                    Memory leaks:  Event listener cleanup 
                    Performance issues:  Profiling and optimization 
                    Module errors:  Import/export syntax 
                    Type errors:  Runtime type checking 
                 
                
                    // Common debugging patterns 
                    // Check if function is called 
                    console.log('Function called with:', arguments); 
                    // Check promise state 
                    promise.then(result => { 
                      console.log('Promise resolved:', result); 
                    }).catch(error => { 
                      console.error('Promise rejected:', error); 
                    }); 
                    // Check object structure 
                    console.log('Object keys:', Object.keys(obj)); 
                    console.log('Object values:', Object.values(obj));
                
             
            
            
                Session Summary 
                
                    Master advanced function concepts and closures 
                    Understand object-oriented programming 
                    Use modern JavaScript features effectively 
                    Handle asynchronous operations properly 
                    Apply functional programming concepts 
                    Write maintainable and testable code 
                 
                
                    Next Session: 
                    Web APIs and External Libraries - Working with third-party services