JavaScript Patterns
Section 4: Intermediate JavaScript Patterns
Lesson 1: Modular JavaScript
Modularizing your JavaScript code is crucial for maintaining a clean and scalable codebase. In this lesson, we'll explore how to organize code into modules, leveraging the power of ES6 modules.
1.1 Organizing Code into Modules
// Module example: module.js
export const add = (a, b) => a + b;
export const subtract = (a, b) => a - b;
// Main file: app.js
import { add, subtract } from './module';
const result1 = add(5, 3);
const result2 = subtract(8, 2);
console.log(result1); // Output: 8
console.log(result2); // Output: 6
1.2 Utilizing ES6 Modules
// ES6 module syntax
// Module example: module.js
export default function multiply(a, b) {
return a * b;
}
// Main file: app.js
import multiply from './module';
const result = multiply(4, 3);
console.log(result); // Output: 12
Lesson 2: Design Patterns for JavaScript
Design patterns provide proven solutions to common development problems. In this lesson, we'll explore and apply some of the most common design patterns in JavaScript.
2.1 Overview of Common Design Patterns
Singleton Pattern: Ensures a class has only one instance and provides a global point of access.
Factory Pattern: Defines an interface for creating an object but allows subclasses to alter the type of objects that will be created.
Observer Pattern: Defines a one-to-many dependency between objects so that when one object changes state, all its dependents are notified.
2.2 Applying Design Patterns in JavaScript
Singleton Pattern
// Singleton pattern example
class Singleton {
constructor() {
if (!Singleton.instance) {
Singleton.instance = this;
}
return Singleton.instance;
}
logMessage(message) {
console.log(message);
}
}
const singletonInstance1 = new Singleton();
singletonInstance1.logMessage('Instance 1 Message');
const singletonInstance2 = new Singleton();
singletonInstance2.logMessage('Instance 2 Message');
console.log(singletonInstance1 === singletonInstance2); // Output: true
Factory Pattern
// Factory pattern example
class Car {
constructor(model) {
this.model = model;
}
}
class CarFactory {
createCar(model) {
return new Car(model);
}
}
const carFactory = new CarFactory();
const car1 = carFactory.createCar('Sedan');
const car2 = carFactory.createCar('SUV');
console.log(car1.model); // Output: Sedan
console.log(car2.model); // Output: SUV
Observer Pattern
// Observer pattern example
class Subject {
constructor() {
this.observers = [];
}
addObserver(observer) {
this.observers.push(observer);
}
notifyObservers(data) {
this.observers.forEach(observer => observer.update(data));
}
}
class Observer {
update(data) {
console.log(`Received update: ${data}`);
}
}
const subject = new Subject();
const observer1 = new Observer();
const observer2 = new Observer();
subject.addObserver(observer1);
subject.addObserver(observer2);
subject.notifyObservers('Data Updated'); // Output: Received update: Data Updated (twice)
In the next section, we'll delve into testing JavaScript applications to ensure code reliability and maintainability.