Callbacks and Higher Order Functions

Instructions: Create a function subtractTwo that accepts a number and returns that number minus 2.

Then create a function map that takes two inputs -

  1. an array of numbers (a list of numbers)
  2. a ‘callback’ function - this function is applied to each element of the array (inside of the function ‘map’)

Have your map function return a new array filled with numbers that are the result of using the ‘callback’ function on each element of the input array. Please do not use the native map or forEach method.


function map(num, callback){
const output = []
for (let i=0; i<output.length; i++){
const updated = callback(map[i]);
output.push(updated);
	}
return output  
}

//callback function
function subtractTwo(map) {
return map[(i -2)]
}


function callback(num) {
return (map[i])
}
 
  
  
  // Uncomment these to check your work!
console.log(typeof subtractTwo); // should log: 'function'
console.log(typeof map); // should log: 'function'
console.log(map([3,4,5], subtractTwo)); // should log: [ 1, 2, 3 ]

So this is my code and i have satisfied 3 of the 4 requirements that are needed but the last requirement is that it should subtract 2 from the array of numbers. Where am i going wrong? I 've been trying to get the answer for hours.

2 Likes

Okay. I see many problems. Let’s start at the beginning. Your subtractTwo function should take a parameter that is a number, but I would not name that parameter ‘map’. This causes confusion because ‘map’ is the name of another function in the same program. Your subtractTwo function should simply return the value of the passed in number minus 2. Something like this:

function subtractTwo(num) {
  return num - 2;
}

If you notice the function call to your map() function that was pre-written in the code editor:

console.log(map([3,4,5], subtractTwo)); // should log: [ 1, 2, 3 ]

You can see that the subtractTwo function is being passed as the second parameter which you have named callback. You do not need this:

Your map() function needs to send each element of the passed in array which you have named num (I would call it ‘nums’ or ‘numArray’ or something to indicate it is a collection of data and not just a single value) to the subtractTwo() function which will return the value minus two, and then save it to your output array. You have a few issues with the elements used inside your function. In your for (...) loop, you want to iterate through the num array, so you need to increment i until it is no longer less than the length of the num array. You currently have it set to terminate after i is no longer less than the length of your empty output array. Inside the for loop we see this:

const updated = callback(map[i]);

What value does map[i] point to? Answer: nothing. map is the name of the function. You want to pass the values of the num array, so callback(num[i]) would do just that.

Give it another shot, and repost your code if you get stuck again. Happy coding!

2 Likes

I actually figured it out just a little before you answered and made all those corrections you spoke of. I was all over the place when i posted this because i felt close, but i made it through. I am still technically in my first week of learning Javascript, so i make some boneheaded mistakes still. You are a lifesaver though my man!! Every time so far i have a question you have come through, it’s people like you that make the online coding community awesome. Keep it up!

3 Likes

That’s awesome that you were able to figure it out on your own. Congratulations! Learning how to debug your own code is crucial to programming. :+1:

2 Likes

Aside

Something to keep in mind when choosing the type of loop… Do we need the index? Is the loop a read-only?

Consider the following, which uses read-only (of):

const map = (nums, callback) => {
  const mapping = [];
  for (let x of nums) {
    mapping.push(callback(x))
  }
  return mapping;
}
const subtractTwo = n => n - 2;
let mapped = map([3,5,7,9], subtractTwo)
console.log(mapped)

Output

[1, 3, 5, 7]
2 Likes

You know, i was actually wondering about that! But i’m just beginning and i don’t know these type of things until someone tells me. So how will i know when to use a read-only(of) loop? Does it default to 0 index? What about increment, decrement? Please understand I’m a newbie in your explanation.

3 Likes

When we only want to read the values in the array, and not iterate over it by index, the for (let x of array) is the way to go for simplicity. x is a value, not an index as it would be in,

for (let x = 0; x < array.length; x++)

In a for…of loop there is no increment/decrement since we are not iterating over the index sequence. JS treats the array not as a sequence, but as a list and keeps iterating until it runs out of values.

If we need to access the values in an array by their index, such as when we wish to mutate zero or more values, then for..of is not the tool to reach for.

3 Likes

Awesome! I understand now. So is it just for simplicity or does it help whatever you are creating execute more efficiently or anything like that?

2 Likes

I don’t know that it is more efficient, but one could reason that it is since there are less moving parts. The internals of for..of may be somewhat simpler than those of for x = 0; ....

Something we always work towards is simplicity for both readability and for ease of maintenance. Also, the more explicit we can write our code, the less chance there is of strange anomalies creeping into our code. Less is more, much of the time.

2 Likes

That was what i assumed. Awesome, thanks. So just to hammer home what you taught me. You are saying anytime you need to just iterate through some values and don’t need to pick a specific index in an array that it better to use this method because it will just iterate over every value in the list. Is that the jist of it?

2 Likes

Yes, pretty much the gist of it. We only wish to poll the values, and not access them for the purpose of possibly changing any.

for..of won’t help us to find the index of the value it has in its sights. We can determine it with the Array.indexOf() method though it is only accurate if we can be certain the value is unique, and not duplicated in the array. The method only finds the first instance, going from left to right. There is also a lastIndexOf method, but that assumes we suspect there is more than one instance. Still, very limited.

for (let i = 0; i < arr.length; i++) 

Above we are not iterating the array, but generating a sequence which corresponds with all the indices of the array. It is that index that lets us access the exact position, and poll its value, and or change it. The above described problem with for..of, that of determining the index of a value, does not exist in this loop since we know the index. It would be this way that we could track down duplicates simply by keeping a temporary array of all the indices where that value can be accessed.

1 Like

A post was split to a new topic: Cant find ware to write it