Mastering Hard Parts of JavaScript: Callbacks IV
Tags: javascript, codenewbie, callbacks
Published: 2020-08-10 21:45:54

---
series: Mastering Hard Parts of JavaScript
description: An introduction to JavaScript callbacks by completing 24 exercises
---
## Exercise 17

> Create a function commutative that accepts two callbacks and a value. commutative will return a boolean indicating if the passing the value into the first function, and then passing the resulting output into the second function, yields the same output as the same operation with the order of the functions reversed (passing the value into the second function, and then passing the output into the first function).

```js
const multBy3 = (n) => n * 3;
const divBy4 = (n) => n / 4;
const subtract5 = (n) => n - 5;
console.log(commutative(multBy3, divBy4, 11));
```

should log `true`

```js
console.log(commutative(multBy3, subtract5, 10));
```

should log `false`

```js
console.log(commutative(divBy4, subtract5, 48));
```

should log `false`

### Solution 17

```js
function commutative(func1, func2, value) {
  return func1(func2(value)) === func2(func1(value)) ? true : false;
}
```

The explanation might look daunting, but once you delve into it, you'll realise that it's actually a rather simple exercise, it just requires good understanding of callbacks (which is the point of all of these really!) The question is, if we pass the value to the first function, is the result equal to passing it to the second function?

Using the ternary operator for simple statements like this can make the code both concise and readable. Just note that you have to put the return statemtn before the first operand.

## Exercise 18

> Create a function objFilter that accepts an object and a callback. objFilter should make a new object, and then iterate through the passed-in object, using each key as input for the callback. If the output from the callback is equal to the corresponding value, then that key-value pair is copied into the new object. objFilter will return this new object.

```js
const startingObj = {};
startingObj[6] = 3;
startingObj[2] = 1;
startingObj[12] = 4;
const half = (n) => n / 2;
console.log(objFilter(startingObj, half));
```

should log `{ 2: 1, 6: 3 }`

### Solution 18

```js
function objFilter(obj, callback) {
  const newObj = Object.create(null);
  for (let [key, value] of Object.entries(obj)) {
    if (value === callback(parseInt(key))) newObj[key] = value;
  }
  return newObj;
}
```

Once again, because an object is being passed to the function, I find using a for loop easier than an Array method, though the latter is also definitely possible.

The key thing to keep in mind here is that object properties are stored as strings, even if they are just numbers. So when making the comparison, we need to make sure we cast it to the correct type (using parseInt()) to make sure that strict equality passes.

## Exercise 19

> Create a function rating that accepts an array (of functions) and a value. All the functions in the array will return true or false. rating should return the percentage of functions from the array that return true when the value is used as input.

```js
const isEven = (n) => n % 2 === 0;
const greaterThanFour = (n) => n > 4;
const isSquare = (n) => Math.sqrt(n) % 1 === 0;
const hasSix = (n) => n.toString().includes("6");
const checks = [isEven, greaterThanFour, isSquare, hasSix];
console.log(rating(checks, 64));
```

should log `100`

```js
console.log(rating(checks, 66));
```

should log `75`

### Solution 19

```js
function rating(arrOfFuncs, value) {
  let trueCnt = arrOfFuncs.reduce((accum, fn) => {
    if (fn(value)) accum++;
    return accum;
  }, 0);
  return (trueCnt / arrOfFuncs.length) * 100;
}
```

An array of functions can look a bit intimidating at first, but it's just an array! So we are taking in an array, and we want a single value to be computed from the array (the number of times its functions returned true) so we are looking at reduce again! Yay!

Here `accum` is initially set to `0`, and everytime the function inside the array returnes true, we increment it. Finally we do a quick calculation based on the size of the array to turn this count into a percentage and return it.

## Exercise 20

> Create a function pipe that accepts an array (of functions) and a value. pipe should input the value into the first function in the array, and then use the output from that function as input for the second function, and then use the output from that function as input for the third function, and so forth, until we have an output from the last function in the array. pipe should return the final output.

```js
const capitalize = (str) => str.toUpperCase();
const addLowerCase = (str) => str + str.toLowerCase();
const repeat = (str) => str + str;
const capAddlowRepeat = [capitalize, addLowerCase, repeat];
console.log(pipe(capAddlowRepeat, "cat"));
```

should log `'CATcatCATcat'`

### Solution 20

```js
function pipe(arrOfFuncs, value) {
  return arrOfFuncs.reduce((accum, fn) => {
    return fn(accum) || fn(value);
  }, "");
}
```

I admit that I found this exercise difficult at first. The trick is in the callback function inside the reduce. The line `return fn(accum) || fn(value);` means `if fn(accum) return fn(accum) else return fn(value)` But I've seen this condensed format using the `||` operator used a lot in open source projects so I decided to use it here even if to a newbie's eyes, the more descriptive format is more readbale.

The initial `accum` in the reduce is an empty string. If fn(accum) returns empty, then assign it to fn(value). In consecutive calls, fn(accum) will return true, so its new value is returned.