DEV Community

Ryan Ameri
Ryan Ameri

Posted on

Mastering Hard Parts of JavaScript: Callbacks V

Exercise 21

Create a function highestFunc that accepts an object (which will contain functions) and a subject (which is any value). highestFunc should return the key of the object whose associated value (which will be a function) returns the largest number, when the subject is given as input.

const groupOfFuncs = {};
groupOfFuncs.double = (n) => n * 2;
groupOfFuncs.addTen = (n) => n + 10;
groupOfFuncs.inverse = (n) => n * -1;
console.log(highestFunc(groupOfFuncs, 5));
// should log: 'addTen'
console.log(highestFunc(groupOfFuncs, 11));
// should log: 'double'
console.log(highestFunc(groupOfFuncs, -20));
// should log: 'inverse'

Solution 21

function highestFunc(objOfFuncs, subject) {
  let largest = Number.NEGATIVE_INFINITY;
  let rightKey = undefined;
  for (let [key, fn] of Object.entries(objOfFuncs)) {
    if (fn(subject) > largest) {
      largest = fn(subject);
      rightKey = key;
    }
  }
  return rightKey;
}

The important thing here is to note that we need to keep hold of two values, what is the largest number returned from the functions, and what is its key. So we define these two variables and initialize them to temporary values. We then loop through the object using our tried and true Object.entries() method, call the function on the subjct, and check to see if its return value is larger than what we currently have stored. If it is, we store that key, and finally once we have looped over the object, we return that key.

Exercise 22

Create a function, combineOperations, that takes two parameters: a starting value and an array of functions. combineOperations should pass the starting value into the first function in the array. combineOperations should pass the value returned by the first function into the second function, and so on until every function in the array has been called. combineOperations should return the final value returned by the last function in the array.

function add100(num) {
  return num + 100;
}

function divByFive(num) {
  return num / 5;
}

function multiplyByThree(num) {
  return num * 3;
}

function multiplyFive(num) {
  return num * 5;
}

function addTen(num) {
  return num + 10;
}

console.log(combineOperations(0, [add100, divByFive, multiplyByThree]));
// Should output 60 -->
console.log(combineOperations(0, [divByFive, multiplyFive, addTen]));
// Should output 10

Solution 22

function combineOperations(startVal, arrOfFuncs) {
  return arrOfFuncs.reduce((accum, fn) => {
    return fn(accum);
  }, startVal);
}

Again, we are being given an array, and we want a single value computed from that array, so we are looking at reduce. This is very similar to exercise 20. The only thing to note here is that we can set the accum of reduce to startVal when we create our reduce.

Exercise 23

Define a function myFunc that takes an array and a callback. myFunc should pass each element from the array (in order) into the callback. If the callback returns true, myFunc should return the index of the current element. If the callback never returns true, myFunc should return -1;

const numbers = [2, 3, 6, 64, 10, 8, 12];
const evens = [2, 4, 6, 8, 10, 12, 64];

function isOddAgain(num) {
  return num % 2 !== 0;
}

console.log(myFunc(numbers, isOddAgain));
// Output should be 1
console.log(myFunc(evens, isOddAgain));
// Output should be -1

Solution 23

function myFunc(array, callback) {
  return array.findIndex(callback);
}

At first I was going to implement the functionality manually using reduce (I think I'm overusing reduce at this point!) but then I looked at the definition again: return the first index if found, return -1 if not found. I realised that this was the definition of the findIndex() Array method, so all we need to do is run findIndex in the input array using the callback. Simple!

Exercise 24

Write a function myForEach that accepts an array and a callback function. Your function should pass each element of the array (in order) into the callback function. The behavior of this function should mirror the functionality of the native .forEach() JavaScript array method as closely as possible.

let sum = 0;

function addToSum(num) {
  sum += num;
}

const nums2 = [1, 2, 3];
myForEach(nums2, addToSum);
console.log(sum);
// Should output 6

Solution 24

function myForEach(array, callback) {
  for (let item of array) {
    callback(item);
  }
}

A bit of a throwback to the earlier exercises, implementing forEach manually again. The only difference is that we're manipulating the variable sum in the global scope here. I decided that using array.forEach() to create my own forEach was cheating 😉 so used a for... of loop instead.

If you found this last exercise very easy, you should see how far you have come since the first exercise in using callbacks and just being comfortable with them.

That's the end of our callback exercises. Next up: Closure!

Top comments (2)

Collapse
 
ramn_ruiz_dev profile image
Ramón Ruiz • Edited

Alternative solution to 24. In order to be as much as possible similar to native implementation:

  1. Add implementation to prototype
  2. Accept same arguments as original forEach (element, index and array):
function myForEach(callback) {
  for(let i = 0; i < this.length; i++) {
      callback(this[i], i, this)
  }
}
Object.defineProperty(Array.prototype, 'myForEach', {
    value: myForEach 
});
Enter fullscreen mode Exit fullscreen mode
Collapse
 
philosphi profile image
Phi Nguyen

Alternate solution to 21:

The max is initialized to be the output of the first function.
In the reduce, the initial acc value is the first function.
For the remaining functions, acc and max are updated whenever their output is greater than the current max

function highestFunc(objOfFuncs, subject) {
  const objKeys = Object.keys(objOfFuncs)
  let max = objOfFuncs[objKeys[0]](subject)
  return objKeys.reduce((acc, key) => {
    let value = objOfFuncs[key](subject)
    if (value > max) {
      acc = key
      max = value
    };
    return acc
  })
}
Enter fullscreen mode Exit fullscreen mode