javascript
exercises
exercises.jsā”javascript
// āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
// ā COMMONJS & AMD - EXERCISES ā
// ā Practice Legacy Module System Patterns ā
// āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
/*
āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
ā EXERCISE OVERVIEW ā
āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā¤
ā ā
ā Exercise 1: CommonJS Module - Create a utility module ā
ā Exercise 2: CommonJS Exports - Practice different export patterns ā
ā Exercise 3: AMD Module - Create modules with dependencies ā
ā Exercise 4: UMD Pattern - Make a universal module ā
ā Exercise 5: Module Conversion - Convert between formats ā
ā ā
āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
*/
// āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
// HELPER: Module System Simulators
// āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
// CommonJS Simulator
const CommonJS = (function () {
const cache = new Map();
return {
createModule(factory) {
const module = { exports: {} };
const exports = module.exports;
factory(module, exports, this.createModule.bind(this));
return module.exports;
},
require(name, factory) {
if (cache.has(name)) {
return cache.get(name);
}
const exports = this.createModule(factory);
cache.set(name, exports);
return exports;
},
clearCache() {
cache.clear();
},
};
})();
// AMD Simulator
const AMD = (function () {
const modules = new Map();
return {
define(name, deps, factory) {
if (typeof name !== 'string') {
factory = deps;
deps = name;
name = 'anonymous_' + Date.now();
}
if (!Array.isArray(deps)) {
factory = deps;
deps = [];
}
if (typeof factory !== 'function') {
const obj = factory;
factory = () => obj;
}
modules.set(name, { deps, factory, resolved: null });
return name;
},
require(deps, callback) {
if (typeof deps === 'string') deps = [deps];
const resolved = deps.map((dep) => {
const mod = modules.get(dep);
if (!mod) throw new Error(`Module not found: ${dep}`);
if (!mod.resolved) {
const depsResolved = mod.deps.map((d) => {
const m = modules.get(d);
return m ? m.resolved || m.factory() : undefined;
});
mod.resolved = mod.factory(...depsResolved);
}
return mod.resolved;
});
if (callback) callback(...resolved);
return resolved[0];
},
clear() {
modules.clear();
},
};
})();
// āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
// EXERCISE 1: CommonJS String Utilities Module
// āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
/*
āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
ā Create a CommonJS string utilities module ā
ā ā
ā Requirements: ā
ā 1. Export a 'capitalize' function that capitalizes first letter ā
ā 2. Export a 'camelCase' function that converts to camelCase ā
ā 3. Export a 'snakeCase' function that converts to snake_case ā
ā 4. Export a 'kebabCase' function that converts to kebab-case ā
ā 5. Export a 'truncate' function with length and suffix parameters ā
ā 6. Export a 'wordCount' function that counts words ā
ā ā
ā Use module.exports = { ... } pattern ā
ā ā
āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
*/
// Your solution here:
const stringUtils = CommonJS.createModule((module, exports) => {
// TODO: Implement the string utilities
// Solution:
function capitalize(str) {
if (!str) return '';
return str.charAt(0).toUpperCase() + str.slice(1).toLowerCase();
}
function camelCase(str) {
return str
.toLowerCase()
.replace(/[^a-zA-Z0-9]+(.)/g, (match, char) => char.toUpperCase());
}
function snakeCase(str) {
return str
.replace(/([a-z])([A-Z])/g, '$1_$2')
.replace(/[\s-]+/g, '_')
.toLowerCase();
}
function kebabCase(str) {
return str
.replace(/([a-z])([A-Z])/g, '$1-$2')
.replace(/[\s_]+/g, '-')
.toLowerCase();
}
function truncate(str, length, suffix = '...') {
if (str.length <= length) return str;
return str.slice(0, length - suffix.length) + suffix;
}
function wordCount(str) {
return str.trim().split(/\s+/).filter(Boolean).length;
}
// Export using module.exports
module.exports = {
capitalize,
camelCase,
snakeCase,
kebabCase,
truncate,
wordCount,
};
});
// Test
console.log('Exercise 1 - CommonJS String Utilities:');
console.log(' capitalize("hello"):', stringUtils.capitalize('hello'));
console.log(
' camelCase("hello world"):',
stringUtils.camelCase('hello world')
);
console.log(' snakeCase("helloWorld"):', stringUtils.snakeCase('helloWorld'));
console.log(
' kebabCase("hello_world"):',
stringUtils.kebabCase('hello_world')
);
console.log(
' truncate("Hello World", 8):',
stringUtils.truncate('Hello World', 8)
);
console.log(
' wordCount("The quick brown fox"):',
stringUtils.wordCount('The quick brown fox')
);
console.log('');
// āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
// EXERCISE 2: CommonJS Export Patterns
// āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
/*
āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
ā Practice different CommonJS export patterns ā
ā ā
ā Task A: Export a single function (factory pattern) ā
ā - Create a 'createCounter' module that exports a factory function ā
ā - Factory returns an object with: increment, decrement, getCount, reset ā
ā ā
ā Task B: Export a class ā
ā - Create an 'EventEmitter' module that exports a class ā
ā - Class has: on(event, handler), emit(event, data), off(event, handler) ā
ā ā
ā Task C: Export using 'exports' shorthand ā
ā - Create a 'validators' module using exports.xxx = ... ā
ā - Include: isEmail, isUrl, isPhone, isEmpty ā
ā ā
āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
*/
// Task A: Factory function export
const counterModule = CommonJS.createModule((module, exports) => {
// TODO: Export createCounter factory function
// Solution:
function createCounter(initialValue = 0) {
let count = initialValue;
return {
increment(amount = 1) {
count += amount;
return count;
},
decrement(amount = 1) {
count -= amount;
return count;
},
getCount() {
return count;
},
reset() {
count = initialValue;
return count;
},
};
}
// Export single function
module.exports = createCounter;
});
console.log('Exercise 2A - Factory Function Export:');
const counter = counterModule(10);
console.log(' Initial count:', counter.getCount());
console.log(' After increment:', counter.increment());
console.log(' After increment(5):', counter.increment(5));
console.log(' After decrement:', counter.decrement());
console.log(' After reset:', counter.reset());
console.log('');
// Task B: Class export
const eventEmitterModule = CommonJS.createModule((module, exports) => {
// TODO: Export EventEmitter class
// Solution:
class EventEmitter {
constructor() {
this.events = new Map();
}
on(event, handler) {
if (!this.events.has(event)) {
this.events.set(event, new Set());
}
this.events.get(event).add(handler);
return this;
}
emit(event, data) {
const handlers = this.events.get(event);
if (handlers) {
handlers.forEach((handler) => handler(data));
}
return this;
}
off(event, handler) {
const handlers = this.events.get(event);
if (handlers) {
handlers.delete(handler);
}
return this;
}
once(event, handler) {
const onceHandler = (data) => {
this.off(event, onceHandler);
handler(data);
};
return this.on(event, onceHandler);
}
}
// Export class
module.exports = EventEmitter;
});
console.log('Exercise 2B - Class Export:');
const emitter = new eventEmitterModule();
emitter.on('greet', (name) => console.log(` Hello, ${name}!`));
emitter.emit('greet', 'World');
console.log('');
// Task C: exports shorthand
const validators = CommonJS.createModule((module, exports) => {
// TODO: Use exports.xxx = ... pattern
// Solution:
exports.isEmail = function (str) {
return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(str);
};
exports.isUrl = function (str) {
try {
new URL(str);
return true;
} catch {
return false;
}
};
exports.isPhone = function (str) {
return /^[\+]?[(]?[0-9]{3}[)]?[-\s.]?[0-9]{3}[-\s.]?[0-9]{4,6}$/.test(str);
};
exports.isEmpty = function (value) {
if (value === null || value === undefined) return true;
if (typeof value === 'string') return value.trim() === '';
if (Array.isArray(value)) return value.length === 0;
if (typeof value === 'object') return Object.keys(value).length === 0;
return false;
};
exports.isNumber = function (value) {
return typeof value === 'number' && !isNaN(value);
};
});
console.log('Exercise 2C - exports Shorthand:');
console.log(
' isEmail("test@email.com"):',
validators.isEmail('test@email.com')
);
console.log(' isEmail("invalid"):', validators.isEmail('invalid'));
console.log(
' isUrl("https://example.com"):',
validators.isUrl('https://example.com')
);
console.log(' isPhone("123-456-7890"):', validators.isPhone('123-456-7890'));
console.log(' isEmpty(""):', validators.isEmpty(''));
console.log(' isEmpty([1,2,3]):', validators.isEmpty([1, 2, 3]));
console.log('');
// āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
// EXERCISE 3: AMD Modules with Dependencies
// āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
/*
āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
ā Create AMD modules with dependencies ā
ā ā
ā Requirements: ā
ā 1. Create 'constants' module with PI, E, GOLDEN_RATIO ā
ā 2. Create 'mathOps' module depending on 'constants' ā
ā - circleArea(r), sphereVolume(r), goldenRectangle(width) ā
ā 3. Create 'formatter' module (no dependencies) ā
ā - formatNumber(n, decimals), formatPercent(n) ā
ā 4. Create 'calculator' module depending on 'mathOps' and 'formatter' ā
ā - calculateAndFormat methods combining both ā
ā ā
āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
*/
// Clear AMD registry for clean start
AMD.clear();
// TODO: Define the AMD modules
// Solution:
// 1. Constants module (no dependencies)
AMD.define('constants', [], function () {
return {
PI: 3.14159265359,
E: 2.71828182846,
GOLDEN_RATIO: 1.61803398875,
};
});
// 2. Math operations module (depends on constants)
AMD.define('mathOps', ['constants'], function (constants) {
return {
circleArea(radius) {
return constants.PI * radius * radius;
},
circleCircumference(radius) {
return 2 * constants.PI * radius;
},
sphereVolume(radius) {
return (4 / 3) * constants.PI * Math.pow(radius, 3);
},
goldenRectangle(width) {
return {
width: width,
height: width / constants.GOLDEN_RATIO,
};
},
exponential(base, power) {
return Math.pow(constants.E, power) * base;
},
};
});
// 3. Formatter module (no dependencies)
AMD.define('formatter', [], function () {
return {
formatNumber(num, decimals = 2) {
return num.toFixed(decimals);
},
formatPercent(num, decimals = 1) {
return (num * 100).toFixed(decimals) + '%';
},
formatCurrency(num, currency = '$') {
return currency + num.toFixed(2);
},
formatWithCommas(num) {
return num.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ',');
},
};
});
// 4. Calculator module (depends on mathOps and formatter)
AMD.define(
'calculator',
['mathOps', 'formatter'],
function (mathOps, formatter) {
return {
calculateCircle(radius) {
const area = mathOps.circleArea(radius);
const circumference = mathOps.circleCircumference(radius);
return {
radius: radius,
area: formatter.formatNumber(area),
circumference: formatter.formatNumber(circumference),
};
},
calculateSphere(radius) {
const volume = mathOps.sphereVolume(radius);
return {
radius: radius,
volume: formatter.formatNumber(volume),
};
},
calculateGoldenRect(width) {
const rect = mathOps.goldenRectangle(width);
return {
width: formatter.formatNumber(rect.width),
height: formatter.formatNumber(rect.height),
ratio: formatter.formatNumber(rect.width / rect.height),
};
},
};
}
);
// Test
console.log('Exercise 3 - AMD Modules with Dependencies:');
AMD.require(['calculator'], function (calc) {
console.log(' Circle (r=5):', calc.calculateCircle(5));
console.log(' Sphere (r=3):', calc.calculateSphere(3));
console.log(' Golden Rectangle (w=100):', calc.calculateGoldenRect(100));
});
AMD.require(['constants', 'formatter'], function (constants, formatter) {
console.log(' PI formatted:', formatter.formatNumber(constants.PI, 5));
console.log(
' Golden Ratio:',
formatter.formatNumber(constants.GOLDEN_RATIO, 5)
);
});
console.log('');
// āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
// EXERCISE 4: UMD Pattern Implementation
// āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
/*
āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
ā Create a UMD (Universal Module Definition) module ā
ā ā
ā Requirements: ā
ā 1. Create a 'DateHelper' utility module ā
ā 2. Should work in: AMD, CommonJS, and browser globals ā
ā 3. Include methods: ā
ā - format(date, pattern) - format date as string ā
ā - parse(str) - parse string to date ā
ā - addDays(date, days) - add days to date ā
ā - diffDays(date1, date2) - difference in days ā
ā - isToday(date), isFuture(date), isPast(date) ā
ā ā
āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
*/
// TODO: Implement UMD module
// Solution:
(function (root, factory) {
// AMD
if (typeof AMD !== 'undefined' && AMD.define) {
AMD.define('dateHelper', [], factory);
}
// CommonJS
else if (typeof module === 'object' && module.exports) {
module.exports = factory();
}
// Browser globals
else {
root.DateHelper = factory();
}
})(typeof globalThis !== 'undefined' ? globalThis : this, function () {
// Private helpers
function padZero(num) {
return String(num).padStart(2, '0');
}
function toDate(value) {
if (value instanceof Date) return value;
return new Date(value);
}
// Public API
return {
format(date, pattern = 'YYYY-MM-DD') {
const d = toDate(date);
const year = d.getFullYear();
const month = padZero(d.getMonth() + 1);
const day = padZero(d.getDate());
const hours = padZero(d.getHours());
const minutes = padZero(d.getMinutes());
const seconds = padZero(d.getSeconds());
return pattern
.replace('YYYY', year)
.replace('MM', month)
.replace('DD', day)
.replace('HH', hours)
.replace('mm', minutes)
.replace('ss', seconds);
},
parse(str) {
return new Date(str);
},
addDays(date, days) {
const result = toDate(date);
result.setDate(result.getDate() + days);
return result;
},
subtractDays(date, days) {
return this.addDays(date, -days);
},
diffDays(date1, date2) {
const d1 = toDate(date1);
const d2 = toDate(date2);
const diffTime = Math.abs(d2 - d1);
return Math.ceil(diffTime / (1000 * 60 * 60 * 24));
},
isToday(date) {
const d = toDate(date);
const today = new Date();
return d.toDateString() === today.toDateString();
},
isFuture(date) {
return toDate(date) > new Date();
},
isPast(date) {
return toDate(date) < new Date();
},
isWeekend(date) {
const day = toDate(date).getDay();
return day === 0 || day === 6;
},
startOfDay(date) {
const d = toDate(date);
d.setHours(0, 0, 0, 0);
return d;
},
endOfDay(date) {
const d = toDate(date);
d.setHours(23, 59, 59, 999);
return d;
},
};
});
// Test via AMD
console.log('Exercise 4 - UMD Module:');
AMD.require(['dateHelper'], function (dateHelper) {
const now = new Date();
console.log(' format(now):', dateHelper.format(now));
console.log(
' format(now, "DD/MM/YYYY"):',
dateHelper.format(now, 'DD/MM/YYYY')
);
console.log(
' addDays(now, 7):',
dateHelper.format(dateHelper.addDays(now, 7))
);
console.log(' isToday(now):', dateHelper.isToday(now));
console.log(
' isFuture(tomorrow):',
dateHelper.isFuture(dateHelper.addDays(now, 1))
);
console.log(' isWeekend(now):', dateHelper.isWeekend(now));
console.log(
' diffDays between dates:',
dateHelper.diffDays('2024-01-01', '2024-01-15'),
'days'
);
});
console.log('');
// āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
// EXERCISE 5: Module Format Conversion
// āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
/*
āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
ā Practice converting between module formats ā
ā ā
ā Given this ES Module code: ā
ā ā
ā export const VERSION = '1.0.0'; ā
ā ā
ā export function greet(name) { ā
ā return `Hello, ${name}!`; ā
ā } ā
ā ā
ā export default class Greeter { ā
ā constructor(greeting = 'Hello') { ā
ā this.greeting = greeting; ā
ā } ā
ā greet(name) { ā
ā return `${this.greeting}, ${name}!`; ā
ā } ā
ā } ā
ā ā
ā Task: Convert to CommonJS, AMD, and UMD formats ā
ā ā
āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
*/
console.log('Exercise 5 - Module Format Conversion:');
// A) CommonJS Version
console.log('\n A) CommonJS Version:');
const greeterCJS = CommonJS.createModule((module, exports) => {
// Named exports
exports.VERSION = '1.0.0';
exports.greet = function (name) {
return `Hello, ${name}!`;
};
// Default export (as main export or separate)
class Greeter {
constructor(greeting = 'Hello') {
this.greeting = greeting;
}
greet(name) {
return `${this.greeting}, ${name}!`;
}
}
// Option 1: Export class as default
module.exports = Greeter;
// Attach named exports to class
module.exports.VERSION = '1.0.0';
module.exports.greet = function (name) {
return `Hello, ${name}!`;
};
});
const GreeterCJS = greeterCJS;
const greeterInstance = new GreeterCJS('Hi');
console.log(' greet("World"):', GreeterCJS.greet('World'));
console.log(
' new Greeter().greet("World"):',
greeterInstance.greet('World')
);
console.log(' VERSION:', GreeterCJS.VERSION);
// B) AMD Version
console.log('\n B) AMD Version:');
AMD.define('greeterAMD', [], function () {
var VERSION = '1.0.0';
function greet(name) {
return 'Hello, ' + name + '!';
}
function Greeter(greeting) {
this.greeting = greeting || 'Hello';
}
Greeter.prototype.greet = function (name) {
return this.greeting + ', ' + name + '!';
};
// Return object with all exports
return {
VERSION: VERSION,
greet: greet,
default: Greeter,
Greeter: Greeter, // Also as named export
};
});
AMD.require(['greeterAMD'], function (greeterModule) {
console.log(' greet("World"):', greeterModule.greet('World'));
var g = new greeterModule.Greeter('Hey');
console.log(' new Greeter("Hey").greet("World"):', g.greet('World'));
console.log(' VERSION:', greeterModule.VERSION);
});
// C) UMD Version
console.log('\n C) UMD Version:');
(function (root, factory) {
if (typeof AMD !== 'undefined' && AMD.define) {
AMD.define('greeterUMD', [], factory);
} else if (typeof module === 'object' && module.exports) {
module.exports = factory();
} else {
root.GreeterModule = factory();
}
})(typeof globalThis !== 'undefined' ? globalThis : this, function () {
var VERSION = '1.0.0';
function greet(name) {
return 'Hello, ' + name + '!';
}
function Greeter(greeting) {
this.greeting = greeting || 'Hello';
}
Greeter.prototype.greet = function (name) {
return this.greeting + ', ' + name + '!';
};
// For UMD, typically export the main thing and attach extras
Greeter.VERSION = VERSION;
Greeter.greet = greet;
return Greeter;
});
AMD.require(['greeterUMD'], function (Greeter) {
console.log(' static greet("World"):', Greeter.greet('World'));
var g = new Greeter('Howdy');
console.log(' new Greeter("Howdy").greet("World"):', g.greet('World'));
console.log(' VERSION:', Greeter.VERSION);
});
console.log('');
// āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
// BONUS EXERCISE: Plugin System
// āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
/*
āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
ā Create a CommonJS-style plugin system ā
ā ā
ā Requirements: ā
ā 1. Create a PluginManager that can: ā
ā - register(name, plugin) - add a plugin ā
ā - unregister(name) - remove a plugin ā
ā - execute(name, ...args) - run a plugin ā
ā - list() - list all plugins ā
ā 2. Plugins are modules that export an 'execute' function ā
ā 3. Create 2-3 sample plugins ā
ā ā
āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
*/
console.log('Bonus - Plugin System:');
const PluginManager = CommonJS.createModule((module, exports) => {
const plugins = new Map();
module.exports = {
register(name, plugin) {
if (typeof plugin.execute !== 'function') {
throw new Error(`Plugin ${name} must have an execute function`);
}
plugins.set(name, plugin);
console.log(` [PluginManager] Registered: ${name}`);
return this;
},
unregister(name) {
plugins.delete(name);
console.log(` [PluginManager] Unregistered: ${name}`);
return this;
},
execute(name, ...args) {
const plugin = plugins.get(name);
if (!plugin) {
throw new Error(`Plugin not found: ${name}`);
}
return plugin.execute(...args);
},
list() {
return Array.from(plugins.keys());
},
has(name) {
return plugins.has(name);
},
};
});
// Sample plugins
const uppercasePlugin = CommonJS.createModule((module) => {
module.exports = {
name: 'uppercase',
version: '1.0.0',
execute(text) {
return text.toUpperCase();
},
};
});
const reversePlugin = CommonJS.createModule((module) => {
module.exports = {
name: 'reverse',
version: '1.0.0',
execute(text) {
return text.split('').reverse().join('');
},
};
});
const repeatPlugin = CommonJS.createModule((module) => {
module.exports = {
name: 'repeat',
version: '1.0.0',
execute(text, times = 2) {
return text.repeat(times);
},
};
});
// Use the plugin system
PluginManager.register('uppercase', uppercasePlugin);
PluginManager.register('reverse', reversePlugin);
PluginManager.register('repeat', repeatPlugin);
console.log(' Available plugins:', PluginManager.list());
console.log(
' uppercase("hello"):',
PluginManager.execute('uppercase', 'hello')
);
console.log(' reverse("hello"):', PluginManager.execute('reverse', 'hello'));
console.log(' repeat("hi", 3):', PluginManager.execute('repeat', 'hi', 3));
console.log('');
// āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
// SUMMARY
// āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
console.log(`
āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
ā COMMONJS & AMD EXERCISES - COMPLETE ā
ā āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā£
ā ā
ā Completed Exercises: ā
ā ā Exercise 1: CommonJS String Utilities ā
ā ā Exercise 2: CommonJS Export Patterns (factory, class, exports) ā
ā ā Exercise 3: AMD Modules with Dependencies ā
ā ā Exercise 4: UMD Pattern Implementation ā
ā ā Exercise 5: Module Format Conversion ā
ā ā Bonus: Plugin System ā
ā ā
ā Key Patterns: ā
ā ⢠CommonJS: module.exports = value, require('module') ā
ā ⢠AMD: define(name, deps, factory), require(deps, callback) ā
ā ⢠UMD: Check for AMD, then CommonJS, then global ā
ā ā
ā Best Practices: ā
ā ⢠Use module.exports for single exports ā
ā ⢠Use exports.x for multiple named exports ā
ā ⢠Never reassign exports directly ā
ā ⢠Declare dependencies explicitly in AMD ā
ā ⢠Use UMD for library distribution ā
ā ā
āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
`);