Practice test for HOF/ Recursion assessment
- A function that takes one or more functions as arguments
- Or returns a function as its result
- Treats functions as first-class citizens
// Takes a function as argument
function higherOrderFunc(callback) {
callback();
}
// Returns a function
function createMultiplier(multiplier) {
return function(x) {
return x * multiplier;
};
}map()- transforms each element in an arrayfilter()- selects elements that meet a conditionreduce()- reduces array to a single valueforEach()- executes a function for each element
- A function passed into another function as an argument
- Executed inside the outer function
- Used for asynchronous operations, event handling, etc.
// Simple callback
function greet(name, callback) {
console.log(`Hello, ${name}!`);
callback();
}
function sayGoodbye() {
console.log("Goodbye!");
}
greet("Alice", sayGoodbye);- A function that calls itself
- Must have a base case to stop recursion
- Each call should work on a smaller problem
// Factorial
function factorial(n) {
if (n <= 1) return 1; // Base case
return n * factorial(n - 1); // Recursive case
}
// Fibonacci
function fibonacci(n) {
if (n <= 1) return n;
return fibonacci(n - 1) + fibonacci(n - 2);
}- Recursion can be more elegant but may use more memory
- Some problems are naturally recursive (tree traversal, etc.)
- Watch for stack overflow with deep recursion
- Forgetting the base case in recursion (infinite recursion)
- Not returning from recursive calls
- Callback hell/pyramid of doom (nested callbacks)
- Assuming callbacks execute immediately (they often don't in async code)
- A compiler optimization that reuses the current stack frame for a recursive call when:
- The recursive call is the last operation in the function (tail position)
- There's no additional computation after the recursive call
- The return value is directly returned from the recursive call
- Prevents stack overflow for deep recursion
- Reduces memory usage
- Enables efficient recursive solutions to problems
Non-Tail Call (Not optimized):
function factorial(n) {
if (n <= 1) return 1;
return n * factorial(n - 1); // Multiplication happens after recursion
}Tail Call Version (Optimizable):
function factorial(n, accumulator = 1) {
if (n <= 1) return accumulator;
return factorial(n - 1, n * accumulator); // No operations after recursion
}- The recursive call must be in tail position
- No operations can occur after the recursive call
- The recursive call must return its value directly
Purpose: Transform each element in an array
Syntax:
// Traditional function
array.map(function(element, index, array) {
return transformedElement;
});
// Arrow function
array.map((element, index, array) => transformedElement);Purpose: Select elements that meet a condition
Syntax:
// Traditional function
array.filter(function(element, index, array) {
return condition;
});
// Arrow function
array.filter((element, index, array) => condition);Purpose: Reduce array to a single value
Syntax:
// Traditional function
array.reduce(function(accumulator, current, index, array) {
return updatedAccumulator;
}, initialValue);
// Arrow function
array.reduce((acc, current, index, array) => updatedAccumulator, initialValue);Purpose: Execute a function for each element
Syntax:
// Traditional function
array.forEach(function(element, index, array) {
// perform operation
});
// Arrow function
array.forEach((element, index, array) => {
// perform operation
});Purpose: Find first element that matches condition
Syntax:
// Traditional function
array.find(function(element, index, array) {
return condition;
});
// Arrow function
array.find((element, index, array) => condition);Purpose: Test if any element passes condition
Syntax:
// Traditional function
array.some(function(element, index, array) {
return condition;
});
// Arrow function
array.some((element, index, array) => condition);Purpose: Test if all elements pass condition
Syntax:
// Traditional function
array.every(function(element, index, array) {
return condition;
});
// Arrow function
array.every((element, index, array) => condition);Purpose: Sort array elements
Syntax:
// Traditional function
array.sort(function(a, b) {
return a - b; // For numbers
});
// Arrow function
array.sort((a, b) => a - b);Traditional:
const squared = numbers.map(function(num) {
return num * num;
});
const evens = numbers.filter(function(num) {
return num % 2 === 0;
});Arrow Functions:
const squared = numbers.map(num => num * num);
const evens = numbers.filter(num => num % 2 === 0);| Method | Best For | Returns |
|---|---|---|
map() |
Transforming data | New array |
filter() |
Selecting subset of data | New array |
reduce() |
Aggregating values | Single value |
forEach() |
Side effects (no return needed) | undefined |
find() |
Finding first matching element | Element or undefined |
some() |
Checking if any elements match | Boolean |
every() |
Checking if all elements match | Boolean |
Purpose: Transform each element in an array
Syntax:
// Traditional function
const squared = [1, 2, 3].map(function(num) {
return num * num;
});
// squared = [1, 4, 9]
// Arrow function
const doubled = [1, 2, 3].map(num => num * 2);
// doubled = [2, 4, 6]Purpose: Select elements that meet a condition
Syntax:
// Traditional function
const evens = [1, 2, 3, 4].filter(function(num) {
return num % 2 === 0;
});
// evens = [2, 4]
// Arrow function
const shortWords = ['hello', 'hi', 'goodbye'].filter(word => word.length < 5);
// shortWords = ['hi']Purpose: Reduce array to a single value
Syntax:
// Traditional function
const sum = [1, 2, 3].reduce(function(acc, num) {
return acc + num;
}, 0);
// sum = 6
// Arrow function
const product = [1, 2, 3, 4].reduce((acc, num) => acc * num, 1);
// product = 24Purpose: Execute a function for each element
Syntax:
// Traditional function
[1, 2, 3].forEach(function(num) {
console.log(num);
});
// Logs: 1, 2, 3 (returns undefined)
// Arrow function
let total = 0;
[1, 2, 3].forEach(num => total += num);
// total = 6 (returns undefined)Purpose: Find first element that matches condition
Syntax:
// Traditional function
const firstEven = [1, 3, 4, 5, 6].find(function(num) {
return num % 2 === 0;
});
// firstEven = 4
// Arrow function
const firstLongWord = ['hi', 'hello', 'hey'].find(word => word.length > 3);
// firstLongWord = 'hello'Purpose: Test if any element passes condition
Syntax:
// Traditional function
const hasNegative = [1, 2, -3, 4].some(function(num) {
return num < 0;
});
// hasNegative = true
// Arrow function
const hasEven = [1, 3, 5].some(num => num % 2 === 0);
// hasEven = falsePurpose: Test if all elements pass condition
**Syntax:
// Traditional function
const allPositive = [1, 2, 3].every(function(num) {
return num > 0;
});
// allPositive = true
// Arrow function
const allShort = ['hi', 'hey', 'yo'].every(word => word.length < 4);
// allShort = truePurpose: Sort array elements
Syntax:
// Traditional function
const nums = [3, 1, 4, 2].sort(function(a, b) {
return a - b;
});
// nums = [1, 2, 3, 4]
// Arrow function
const words = ['banana', 'apple', 'cherry'].sort((a, b) => a.localeCompare(b));
// words = ['apple', 'banana', 'cherry']// Transform array of temperatures from C to F
const celsius = [0, 15, 30];
const fahrenheit = celsius.map(c => c * 9/5 + 32);
// fahrenheit = [32, 59, 86]
// Filter out falsy values
const mixed = [0, 'hello', '', 42, false];
const truthy = mixed.filter(Boolean);
// truthy = ['hello', 42]
// Count occurrences with reduce
const votes = ['yes', 'no', 'yes', 'yes'];
const tally = votes.reduce((acc, vote) => {
acc[vote] = (acc[vote] || 0) + 1;
return acc;
}, {});
// tally = {yes: 3, no: 1}