4.4 מודולים פתרון
פתרון - מודולים¶
תרגיל 1 - ייצוא וייבוא בסיסיים¶
// stringUtils.js
export function capitalize(str) {
return str.charAt(0).toUpperCase() + str.slice(1);
}
export function reverse(str) {
return str.split("").reverse().join("");
}
export function countWords(str) {
return str.trim().split(/\s+/).length;
}
// mathUtils.js
export function clamp(value, min, max) {
return Math.min(Math.max(value, min), max);
}
export function average(...numbers) {
if (numbers.length === 0) return 0;
const sum = numbers.reduce((acc, n) => acc + n, 0);
return sum / numbers.length;
}
export function isPrime(n) {
if (n < 2) return false;
for (let i = 2; i <= Math.sqrt(n); i++) {
if (n % i === 0) return false;
}
return true;
}
// main.js
import { capitalize, reverse, countWords } from "./stringUtils.js";
import { clamp, average, isPrime } from "./mathUtils.js";
console.log(capitalize("hello")); // "Hello"
console.log(reverse("abc")); // "cba"
console.log(countWords("hello world")); // 2
console.log(clamp(15, 0, 10)); // 10
console.log(average(1, 2, 3, 4)); // 2.5
console.log(isPrime(7)); // true
תרגיל 2 - ייצוא ברירת מחדל¶
// Logger.js
export const LOG_LEVELS = {
INFO: "info",
WARN: "warn",
ERROR: "error"
};
export default class Logger {
constructor(prefix) {
this.prefix = prefix;
}
log(message) {
console.log(`[${this.prefix}] ${message}`);
}
warn(message) {
console.log(`[${this.prefix}] WARNING: ${message}`);
}
error(message) {
console.log(`[${this.prefix}] ERROR: ${message}`);
}
}
// main.js
import Logger, { LOG_LEVELS } from "./Logger.js";
const logger = new Logger("App");
logger.log("Started"); // "[App] Started"
logger.warn("Low memory"); // "[App] WARNING: Low memory"
logger.error("Crash!"); // "[App] ERROR: Crash!"
console.log(LOG_LEVELS.WARN); // "warn"
תרגיל 3 - barrel file¶
// validators/string.js
export function isNotEmpty(str) {
return typeof str === "string" && str.trim().length > 0;
}
export function hasMinLength(str, min) {
return typeof str === "string" && str.length >= min;
}
// validators/number.js
export function isPositive(n) {
return typeof n === "number" && n > 0;
}
export function isInRange(n, min, max) {
return typeof n === "number" && n >= min && n <= max;
}
// validators/email.js
export function isValidEmail(str) {
if (typeof str !== "string") return false;
const parts = str.split("@");
if (parts.length !== 2) return false;
return parts[0].length > 0 && parts[1].includes(".");
}
// validators/index.js (barrel file)
export { isNotEmpty, hasMinLength } from "./string.js";
export { isPositive, isInRange } from "./number.js";
export { isValidEmail } from "./email.js";
// main.js
import { isNotEmpty, isPositive, isValidEmail } from "./validators/index.js";
console.log(isNotEmpty("hello")); // true
console.log(isNotEmpty("")); // false
console.log(isPositive(-5)); // false
console.log(isPositive(10)); // true
console.log(isValidEmail("a@b.com")); // true
console.log(isValidEmail("not-an-email")); // false
תרגיל 4 - שינוי שמות בייבוא¶
// main.js
// import with renamed aliases
import {
format as zeroPad,
parse as toInt,
validate as isDefined
} from "./helpers.js";
console.log(zeroPad(5)); // "05"
console.log(toInt("42")); // 42
console.log(isDefined(null)); // false
console.log(isDefined("hi")); // true
// import everything as an object
import * as helpers from "./helpers.js";
console.log(helpers.format(3)); // "03"
console.log(helpers.parse("100")); // 100
console.log(helpers.validate(0)); // true
תרגיל 5 - ייבוא דינמי¶
async function loadModule(moduleName) {
try {
const module = await import(`./modules/${moduleName}.js`);
return module;
} catch (error) {
console.error(`Failed to load module "${moduleName}":`, error.message);
return null;
}
}
// usage
const math = await loadModule("math");
if (math) {
console.log(math.add(2, 3)); // 5
}
const nonExistent = await loadModule("does-not-exist");
// "Failed to load module "does-not-exist": ..."
console.log(nonExistent); // null
function loadOnClick(buttonId, moduleName) {
const button = document.getElementById(buttonId);
let loaded = false;
button.addEventListener("click", async () => {
if (loaded) {
console.log(`Module "${moduleName}" already loaded`);
return;
}
const module = await loadModule(moduleName);
if (module) {
loaded = true;
console.log(`Module "${moduleName}" loaded successfully`);
// module is now available for use
}
});
}
// usage:
loadOnClick("loadChartBtn", "chart");
שימו לב ל-closure: המשתנה loaded נשמר ב-closure של ה-event handler, ומונע טעינה כפולה.
תרגיל 6 - מערכת פלאגינים עם מודולים¶
// plugins/uppercase.js
export const name = "uppercase";
export const description = "Converts text to uppercase";
export function execute(input) {
return input.toUpperCase();
}
// plugins/reverse.js
export const name = "reverse";
export const description = "Reverses the input string";
export function execute(input) {
return input.split("").reverse().join("");
}
// plugins/wordcount.js
export const name = "wordcount";
export const description = "Returns the number of words in the input";
export function execute(input) {
return input.trim().split(/\s+/).length;
}
// PluginManager.js
class PluginManager {
#plugins = new Map();
async loadPlugin(name) {
try {
const module = await import(`./plugins/${name}.js`);
this.#plugins.set(module.name, {
name: module.name,
description: module.description,
execute: module.execute
});
console.log(`Plugin "${module.name}" loaded`);
} catch (error) {
console.error(`Failed to load plugin "${name}":`, error.message);
}
}
listPlugins() {
return Array.from(this.#plugins.values()).map(p => ({
name: p.name,
description: p.description
}));
}
run(pluginName, input) {
const plugin = this.#plugins.get(pluginName);
if (!plugin) {
throw new Error(`Plugin "${pluginName}" not found`);
}
return plugin.execute(input);
}
}
// usage
const manager = new PluginManager();
await manager.loadPlugin("uppercase");
await manager.loadPlugin("reverse");
await manager.loadPlugin("wordcount");
console.log(manager.listPlugins());
// [
// { name: "uppercase", description: "Converts text to uppercase" },
// { name: "reverse", description: "Reverses the input string" },
// { name: "wordcount", description: "Returns the number of words in the input" }
// ]
console.log(manager.run("uppercase", "hello world")); // "HELLO WORLD"
console.log(manager.run("reverse", "hello")); // "olleh"
console.log(manager.run("wordcount", "one two three")); // 3