Javascripts Callback Functions Exercise - I
Exercise 1
Create a function addTwo that accepts one input and adds 2 to it.
console.log(addTwo(3));should output 5 and
console.log(addTwo(10));should output 12
Solution 1
function addTwo(num) {
return num + 2;
}The most simple exercise. It gives us a nice comforting feeling knowing that we know how to use functions. Don't worry, things will get interesting soon!
Exercise 2
Create a function addS that accepts one input and adds an "s" to it.
console.log(addS("pizza"));should output pizzas and
console.log(addS("bagel"));should output bagels
Solution 2
function addS(word) {
return word + "s";
}Another easy function. Good reminder that + is an overloaded operator in JS that can work with strings and numbers.
Exercise 3
Create a function called map that takes two inputs: an array of numbers (a list of numbers) a 'callback' function - a function that is applied to each element of the array (inside of the function 'map') Have map return a new array filled with numbers that are the result of using the 'callback' function on each element of the input array.
console.log(map([1, 2, 3], addTwo));should output
[ 3, 4, 5 ]Solution 3
function map(array, callback) {
const newArr = [];
for (let i = 0; i < array.length; i++) {
newArr.push(callback(array[i]));
}
return newArr;
}Now this is more interesting! We are basically re-implementing a simple version of the native Array.prototype.map() function here. I decided to use a basic for loop here as most people should be familiar with it. I think this is probably the most important exercise in the series, if you can get head around this, you've basically gotten callbacks!
Exercise 4
The function forEach takes an array and a callback, and runs the callback on each element of the array. forEach does not return anything.
let alphabet = "";
const letters = ["a", "b", "c", "d"];
forEach(letters, function (char) {
alphabet += char;
});
console.log(alphabet);should output abcd
Solution 4
function forEach(array, callback) {
for (let i = 0; i < array.length; i++) {
callback(array[i]);
}
}Another reimplementation of a native Array method. Notice the difference with map, map returns an array, forEach doesn't return anything so whatever needs to happen needs to take place in the body of the callback function.
Exercise 5
Rebuild your map function, this time instead of using a for loop, use your own forEach function that you just defined. Call this new function mapWith.
console.log(mapWith([1, 2, 3], addTwo));should output
[ 3, 4, 5 ]Solution 5
function mapWith(array, callback) {
const newArr = [];
forEach(array, (item) => {
newArr.push(callback(item));
});
return newArr;
}Using your own previously defined function in this manner is very powerful. It allows you to get to grips with how functions exactly work. Now when you use a library such as lodash or underscore, you can imagine how the underlying function is implemented.
Exercise 6
The function reduce takes an array and reduces the elements to a single value. For example it can sum all the numbers, multiply them, or any operation that you can put into a function.
const nums = [4, 1, 3];
const add = function (a, b) {
return a + b;
};
console.log(reduce(nums, add, 0))should output 8.
Solution 6
function reduce(array, callback, initialValue) {
let accum;
if (Object.keys(arguments).length > 2) {
accum = initialValue;
} else {
// InitialValue not provided
accum = array[0];
array.shift();
}
forEach(array, (item) => {
accum = callback(accum, item);
});
return accum;
}Reduce! One of the most misunderstood yet powerful functions in JS (and more broadly in functional programming). The basic concept is this: You have an initial value, you run the callback function on every item in an array, and assign the result to this initial value. At the end, you return this value.
The other gotcha with reduce is that the initialValue parameter is optional, the caller might provide it or not. If it is provided, we should use its value as the initial accumulator of our array. If it's not provided, we should consider the first element of the array as the accumulator. Here we test the number of arguments provided by checking Object.keys(arguments).length and proceed to set our accumulator accordingly.
Exercise 7
Construct a function intersection that compares input arrays and returns a new array with elements found in all of the inputs. BONUS: Use reduce!
console.log(
intersection([5, 10, 15, 20], [15, 88, 1, 5, 7], [1, 10, 15, 5, 20])
);Should output
[5, 15]Solution 7
function intersection(...arrays) {
return arrays.reduce((acc, array) => {
return array.filter((item) => acc.includes(item));
});
}BlogCombining reduce and filter results in a powerful function. Here, if acc is not provided as a param, it is set to the first array, and we are not providing it as an argument. So in subsequent calls we just filter the arrays to return items that were also included in the acc` array. Notice the use of ...arrays, here we are using the rest parameters because we don't know how many arguments will be supplied to the function.