javascript
exercises
exercises.js⚡javascript
/**
* =====================================================
* 5.4 PARAMETERS AND ARGUMENTS - EXERCISES
* =====================================================
* Practice function parameters
*/
/**
* Exercise 1: Default Greeting
*
* Create a function with default parameters for both
* name and greeting.
*/
function greet(name, greeting) {
// TODO: Add default parameters
// Default name: "Guest", greeting: "Hello"
}
// Test cases:
console.log('Exercise 1:');
console.log(greet()); // "Hello, Guest!"
console.log(greet('Alice')); // "Hello, Alice!"
console.log(greet('Bob', 'Hi')); // "Hi, Bob!"
/**
* Exercise 2: Sum All Numbers
*
* Create a function using rest parameters that sums
* any number of arguments.
*/
function sumAll() {
// TODO: Use rest parameters
}
// Test cases:
console.log('\nExercise 2:');
console.log(sumAll(1, 2, 3)); // 6
console.log(sumAll(1, 2, 3, 4, 5)); // 15
console.log(sumAll()); // 0
/**
* Exercise 3: Create User with Options
*
* Create a function that accepts an options object
* with defaults for role, active, and createdAt.
*/
function createUser(options) {
// TODO: Destructure options with defaults
// name: required
// role: "user"
// active: true
// createdAt: new Date()
}
// Test cases:
console.log('\nExercise 3:');
console.log(createUser({ name: 'Alice' }));
// { name: "Alice", role: "user", active: true, createdAt: Date }
console.log(createUser({ name: 'Bob', role: 'admin', active: false }));
/**
* Exercise 4: Array Statistics
*
* Create a function using destructuring in parameters
* that takes [first, ...rest] and returns statistics.
*/
function getStats(numbers) {
// TODO: Use array destructuring
// Return { first, last, count, sum }
}
// Test cases:
console.log('\nExercise 4:');
console.log(getStats([1, 2, 3, 4, 5]));
// { first: 1, last: 5, count: 5, sum: 15 }
/**
* Exercise 5: Merge Objects
*
* Create a function that merges multiple objects using rest.
*/
function mergeObjects() {
// TODO: Use rest parameters and spread
}
// Test cases:
console.log('\nExercise 5:');
console.log(mergeObjects({ a: 1 }, { b: 2 }, { c: 3 }));
// { a: 1, b: 2, c: 3 }
console.log(mergeObjects({ a: 1, b: 2 }, { b: 3, c: 4 }));
// { a: 1, b: 3, c: 4 }
/**
* Exercise 6: Format Price
*
* Create a function with named parameters for formatting prices.
*/
function formatPrice(options) {
// TODO: Destructure with defaults
// amount: required
// currency: "USD"
// locale: "en-US"
// decimals: 2
}
// Test cases:
console.log('\nExercise 6:');
console.log(formatPrice({ amount: 1234.5 })); // "$1,234.50"
console.log(formatPrice({ amount: 1234.5, currency: 'EUR', locale: 'de-DE' }));
/**
* Exercise 7: Required Parameters
*
* Create a required() helper and use it in a function.
*/
function required(paramName) {
// TODO: Throw error with param name
}
function registerUser(username, email, password) {
// TODO: Make username, email, password required
}
// Test cases:
console.log('\nExercise 7:');
try {
registerUser('alice', 'alice@example.com'); // Should throw
} catch (e) {
console.log('Error:', e.message);
}
/**
* Exercise 8: Clone Without Mutation
*
* Create a function that adds properties to an object
* without mutating the original.
*/
function addProperties(obj, properties) {
// TODO: Return new object with added properties
}
// Test cases:
console.log('\nExercise 8:');
const original = { a: 1 };
const updated = addProperties(original, { b: 2, c: 3 });
console.log('Original:', original); // { a: 1 }
console.log('Updated:', updated); // { a: 1, b: 2, c: 3 }
/**
* Exercise 9: Nested Destructuring
*
* Create a function that extracts deeply nested values.
*/
function extractUserInfo(response) {
// TODO: Destructure response.data.user.{name, email}
// and response.status
}
// Test cases:
console.log('\nExercise 9:');
const apiResponse = {
status: 200,
data: {
user: {
name: 'Alice',
email: 'alice@example.com',
preferences: { theme: 'dark' },
},
},
};
console.log(extractUserInfo(apiResponse));
// { name: "Alice", email: "alice@example.com", status: 200 }
/**
* Exercise 10: Logger Function
*
* Create a flexible logger using rest and named parameters.
*/
function createLogger(options) {
// TODO: Return a function that logs with prefix and timestamp
// options: { prefix: "LOG", includeTime: true }
}
// Test cases:
console.log('\nExercise 10:');
const log = createLogger({ prefix: 'APP' });
log('Starting...', 'Loading config');
// [APP] [timestamp] Starting...
// [APP] [timestamp] Loading config
// =====================================================
// INTERMEDIATE EXERCISES
// =====================================================
/**
* Exercise 11: Partial Application
*
* Create a partial function that pre-fills arguments.
*/
function partial(fn, ...presetArgs) {
// TODO: Return function with preset args
}
// Test cases:
console.log('\nExercise 11:');
const add = (a, b, c) => a + b + c;
const addFive = partial(add, 5);
console.log(addFive(3, 2)); // 10
/**
* Exercise 12: Validate Options
*
* Create a function that validates an options object
* against a schema of required and optional fields.
*/
function validateOptions(options, schema) {
// TODO: Validate options against schema
// Return { valid: boolean, errors: string[] }
}
// Test cases:
console.log('\nExercise 12:');
const schema = {
required: ['name', 'email'],
optional: ['age', 'role'],
};
console.log(validateOptions({ name: 'Alice', email: 'a@b.com' }, schema));
// { valid: true, errors: [] }
console.log(validateOptions({ name: 'Alice' }, schema));
// { valid: false, errors: ["email is required"] }
/**
* Exercise 13: Curry with Placeholder
*
* Create a curry function that supports placeholders.
*/
const _ = Symbol('placeholder');
function curry(fn) {
// TODO: Implement curry with placeholder support
}
// Test cases:
console.log('\nExercise 13:');
// const divide = (a, b) => a / b;
// const curriedDivide = curry(divide);
// console.log(curriedDivide(10)(2)); // 5
// console.log(curriedDivide(_, 2)(10)); // 5 (10 / 2)
/**
* Exercise 14: Options Merger
*
* Create a function that deeply merges options with defaults.
*/
function mergeWithDefaults(defaults, options) {
// TODO: Deep merge options over defaults
}
// Test cases:
console.log('\nExercise 14:');
const defaults = {
theme: 'light',
settings: {
notifications: true,
sound: false,
},
};
const userOptions = {
settings: { sound: true },
};
console.log(mergeWithDefaults(defaults, userOptions));
// { theme: "light", settings: { notifications: true, sound: true } }
/**
* Exercise 15: Function Overloading Pattern
*
* Create a function that behaves differently based on
* the number and types of arguments.
*/
function createElement(tagOrConfig, attributes, children) {
// TODO: Handle multiple calling patterns:
// createElement("div")
// createElement("div", { class: "box" })
// createElement("div", { class: "box" }, ["child1", "child2"])
// createElement({ tag: "div", class: "box", children: [...] })
}
// Test cases:
console.log('\nExercise 15:');
// console.log(createElement("div"));
// console.log(createElement("div", { class: "box" }));
// console.log(createElement({ tag: "span", class: "text" }));
// =====================================================
// SOLUTIONS (Uncomment to check your answers)
// =====================================================
/*
// Exercise 1 Solution:
function greet(name = "Guest", greeting = "Hello") {
return `${greeting}, ${name}!`;
}
// Exercise 2 Solution:
function sumAll(...numbers) {
return numbers.reduce((sum, n) => sum + n, 0);
}
// Exercise 3 Solution:
function createUser({ name, role = "user", active = true, createdAt = new Date() }) {
return { name, role, active, createdAt };
}
// Exercise 4 Solution:
function getStats([first, ...rest]) {
const all = [first, ...rest];
return {
first,
last: rest.length > 0 ? rest[rest.length - 1] : first,
count: all.length,
sum: all.reduce((a, b) => a + b, 0)
};
}
// Exercise 5 Solution:
function mergeObjects(...objects) {
return objects.reduce((merged, obj) => ({ ...merged, ...obj }), {});
}
// Exercise 6 Solution:
function formatPrice({ amount, currency = "USD", locale = "en-US", decimals = 2 }) {
return new Intl.NumberFormat(locale, {
style: "currency",
currency,
minimumFractionDigits: decimals,
maximumFractionDigits: decimals
}).format(amount);
}
// Exercise 7 Solution:
function required(paramName) {
throw new Error(`'${paramName}' is required`);
}
function registerUser(
username = required("username"),
email = required("email"),
password = required("password")
) {
return { username, email, password };
}
// Exercise 8 Solution:
function addProperties(obj, properties) {
return { ...obj, ...properties };
}
// Exercise 9 Solution:
function extractUserInfo({ status, data: { user: { name, email } } }) {
return { name, email, status };
}
// Exercise 10 Solution:
function createLogger({ prefix = "LOG", includeTime = true } = {}) {
return (...messages) => {
const time = includeTime ? `[${new Date().toISOString()}]` : "";
messages.forEach(msg => {
console.log(`[${prefix}] ${time} ${msg}`);
});
};
}
// Exercise 11 Solution:
function partial(fn, ...presetArgs) {
return (...laterArgs) => fn(...presetArgs, ...laterArgs);
}
// Exercise 12 Solution:
function validateOptions(options, schema) {
const errors = [];
for (const field of schema.required) {
if (!(field in options)) {
errors.push(`${field} is required`);
}
}
return { valid: errors.length === 0, errors };
}
// Exercise 13 Solution:
function curry(fn) {
const arity = fn.length;
const resolver = (...args) => {
const hasPlaceholder = args.some(a => a === _);
if (args.length >= arity && !hasPlaceholder) {
return fn(...args);
}
return (...nextArgs) => {
const combined = args.map(a =>
a === _ && nextArgs.length ? nextArgs.shift() : a
).concat(nextArgs);
return resolver(...combined);
};
};
return resolver;
}
// Exercise 14 Solution:
function mergeWithDefaults(defaults, options) {
const result = { ...defaults };
for (const key in options) {
if (typeof options[key] === "object" && options[key] !== null &&
typeof result[key] === "object" && result[key] !== null) {
result[key] = mergeWithDefaults(result[key], options[key]);
} else {
result[key] = options[key];
}
}
return result;
}
// Exercise 15 Solution:
function createElement(tagOrConfig, attributes = {}, children = []) {
if (typeof tagOrConfig === "object") {
const { tag, children = [], ...attrs } = tagOrConfig;
return { tag, attributes: attrs, children };
}
return { tag: tagOrConfig, attributes, children };
}
*/