Callbacks and higher-order functions are some of the most misunderstood concepts in JavaScript. In this post, we will become familiar with them to write pro-level code as JavaScript engineers.
A callback function is a function passed into another function as an argument, which is then invoked inside the outer function to complete some sort action.
Callbacks: Using a Function as an Argument
What is a callback?
A callback is always a function that is being passed into another function.
letfoobar=function (callback) {console.log("foo");callback();console.log("bar");};letsayHello=function () {console.log("hello");};foobar(sayHello); // prints// foo// hello// bar
Although we named our parameter callback, we could name it anything we like.
letfoobar=function (callback) {console.log("foo");callback();console.log("bar");};foobar(function () {console.log("hello");}); // prints// foo// hello// bar
Anonymous Callback : When we use a function expression directly.
Typically we want to assign our callback to a name if we plan on using it multiple times, an anonymous callball is better if it's just single use.
A More Interesting Example
letadd=function (num1, num2, cb) {let sum = num1 + num2;let result =cb(sum);return result;};letdouble=function (num) {return num *2;};console.log(add(2,3, double)); // 10
Variable expression function being passed in as an argument.
letadd=function (num1, num2, cb) {let sum = num1 + num2;let result =cb(sum);return result;};console.log(add(60,4,Math.sqrt)); // 8
Math.sqrt built in function being passed directly in as an argument.
Refactoring for an Optional Callback
We can add in a conditional to make the callback optional. (This is a very common pattern in Javascript!)
Given multiple plausible reasons, identify why functions are called โFirst Class Objectsโ in JavaScript. Given a code snippet containing an anonymous callback, a named callback, and multiple console.logs, predict what will be printed Write a function that takes in a value and two callbacks. The function should return the result of the callback that is greater. Write a function, myMap, that takes in an array and a callback as arguments. The function should mimic the behavior of Array#map. Write a function, myFilter, that takes in an array and a callback as arguments. The function should mimic the behavior of Array#filter. Write a function, myEvery, that takes in an array and a callback as arguments. The function should mimic the behavior of Array#every.
// 1. Given multiple plausible reasons, identify why functions are called "First Class Objects" in JavaScript.// Here are some of the reasons:// A function is an instance of the Object type// You can store the function in a variableletnegate=function (num) {return num _ -1;};// You can pass the function as a parameter to another functionfunctionplayer(callback) {console.log('Lebron');callback();}player(function () {console.log('Los Angeles');});// You can return the function from a functionfunctionsport() {return (functionteam() {return"I'm a returned function"})}let newFunc =sport();console.log(newFunc())// 2. Given a code snippet containing an anonymous callback, a named callback, and multiple console.logs, predict what will be printed
functionplayer(callback) {console.log('Lebron');callback();}functionsport() {console.log('Basketball');}constteamInfo=function () {console.log('Lakers');sport();player(sport);player(function () {console.log('Los Angeles');});console.log('California');};teamInfo();// 3. Write a function that takes in a value and two callbacks. The function should return the result of the callback that is greater.
functiongreaterValue(value, cb1, cb2) {// compare cb1 invoked with value to cb2 invoked with value// return the greater resultlet res1 =cb1(value);let res2 =cb2(value);if (res1 > res2) {// if this is false, we move out of if statementreturn res1;}return res2;}letnegate=function (num) {return num _ -1;};letaddOne=function (num) {return num +1;};console.log(greaterValue(3, negate, addOne));console.log(greaterValue(-2, negate, addOne));// 4. Write a function, myMap, that takes in an array and a callback as arguments. The function should mimic the behavior of Array#map.
functionmyMap(arr, callback) {// iterate through the array, perform the cb on each element// return a new array with those new valueslet mapped = [];for (let i =0; i <arr.length; i++) {// remember that map passes three args with each element.let val =callback(arr[i], i, arr);mapped.push(val);}return mapped;}letdouble=function (num) {return num _ 2;};console.log(myMap([1,2,3], double));// 5. Write a function, myFilter, that takes in an array and a callback as arguments. The function should mimic the behavior of Array#filter.
functionmyFilter(arr, callback) {let filtered = [];for (let i =0; i <arr.length; i++) {let element = arr[i];if (callback(element, i, arr)) {filtered.push(element);}}return filtered;}// 6. Write a function, myEvery, that takes in an array and a callback as arguments. The function should mimic the behavior of Array#every.
functionmyEvery(arr, callback) {for (let i =0; i <arr.length; i++) {let element = arr[i];if (callback(element, i, arr) ===false) {returnfalse;}}returntrue;}// Initialize calculation functions to variables to put in array.letadd=function (n1, n2) {return n1 + n2;};letsubtract=function (n1, n2) {return n1 - n2;};letmultiply=function (n1, n2) {return n1 _ n2;};letdivide=function (n1, n2) {return n1 / n2;};letmod=function (n1, n2) {return n1 % n2;};letisDivisible=function (n1, n2) {if (mod(n1, n2) ===0) {returntrue;}returnfalse;};// Initialize array containing calculation functionslet funcArray = [add, subtract, multiply, divide, mod, isDivisible];// Initialize function taking two numbers and an array// of functions as parametersletcalculateAll=function (n1, n2, arrayOfFuncs) {let ansArray = [];arrayOfFuncs.forEach(function (callback) {ansArray.push(callback(n1, n2));});return ansArray;};// Initialize a function taking two numbers, an array// of functions, and a users choice of which to call// as parametersletcalculateChosen=function (n1, n2, arrayOfFuncs, choice) {return arrayOfFuncs[choice](n1, n2);};// Call the function, passing in 10, 2, and an// array of functionsconsole.log(calculateAll(10,2, funcArray));// Call the function, passing in 10, 2, and the// users choice of operationconsole.log(calculateChosen(10,2, funcArray,1));