Function within a function

Hi I just took a 2-3 week break from coding and now returning to this. I think my problem as it was before is that I have trouble using a function within a function or callback functions within a function.

I’ve sadly been struggling with this for some time and I’ve been finding myself struggling to a point where I’m losing interest. I’ve gone back to redo sections like this a few times now. Each time I do this I feel more ambition dripping away.

I’m here now at this problem again and I feel my main issue is effecting me again and I don’t know where exactly the disconnect happens. Hope someone can help, thanks

  **Your code so far**

// The global variable
var s = [23, 65, 98, 5];

Array.prototype.myMap = function(callback) {
var newArray = [];
// Only change code below this line
for(let i = 0; i < s.length; i++) {
  newArray.push(s[i]);
}
// Only change code above this line
return newArray;
};

var new_s = s.myMap(function(item) {
return item * 2;
});

console.log(new_s);
  **Your browser information:**

User Agent is: Mozilla/5.0 (Macintosh; Intel Mac OS X 11_2_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.90 Safari/537.36.

Challenge: Implement map on a Prototype

Link to the challenge:

Do you have a question? Is there something specific?

Looking at what you have, you have the basic components there, you just need to apply the callback function. In JS, functions are just variable, like any other (technically a kind of object).

You are invoking it here:

var new_s = s.myMap(function(item) {
  return item * 2;
});

so you are passing in:

function(item) {
  return item * 2;
}

That is what you are passing in and it is what is getting stored in the parameter callback. Inside your myMap method definition, you can just call that like callback().

To get this to work, I added that to your code, calling callback with the right parameter. I had to add that to one line and got your code to pass.

Does that help?

I just don’t know how to write code taking these callbacks in. I don’t see how they combine. Does that make sense?

Basically I have

Array.prototype.myMap = function(callback) {
  var newArray = [];
  // Only change code below this line
  for(let i = 0; i < s.length; i++) {
    newArray.push(s[i]);
  }
  // Only change code above this line
  return newArray;
};

and

var new_s = s.myMap(function(item) {
  return item * 2;
});

How does

function(item) {
  return item * 2;
});

Get placed into

function(callback) {
  var newArray = [];
  // Only change code below this line
  for(let i = 0; i < s.length; i++) {
    newArray.push(s[i]);
  }
  // Only change code above this line
  return newArray;
};

I’m happy to spend 20 hours a week coding and want to do that, but I can’t seem to learn what I need. I even messaged someone on Twitter and they told me to read this Variable scope, closure but I don’t understand these types of long documents. I’m being honest about my shortcomings hoping I can find a solution. I’d be willing to spend 10 hours just on this concept alone if need be

This challenge is a bit tricky because you need to use this because you are writing a function that works for all arrays.

Also, I don’t see where you are using the callback.


Pulling back to a ‘big picture’, this challenge is asking you to make a new method that will work on all arrays.

All arrays have certain built in properties and methods, like length, map(), every(), etc. You need to make a new method that works for every single array. We do this by adding a new method to the prototype for every array.

Array.prototype.myNewMethodForAllArrays = function(.........) { .... }

Since you are trying to make a new method that operates on the elements of an array, you need a way to access the array and its elements. This is what this does for you.

let s = [23, 65, 98, 5];
// I can't write the function to refer to s
// because then it would only work for 
// *one* array, not *all* arrays
s.myNewMethodForAllArrays(....) 

Now, another big picture idea is that functions can be passed around just like arrays or objects. You can give a function as an argument to another function. Look at this

// Print the numbers 1-5 with custom formatting
function printOneToFive(callback) {
  for (let i = 1; i <= 5; i++) {
    console.log(callback(i));
  }
}

// A nice formatting function
function makePretty(num) {
  return "--*****--" + num + "--*****--";
}

// A bad formatting function
function makeMessy(num) {
  return "890721498721948" + num + "98127498";
}

// Test
printOneToFive(makePretty);
printOneToFive(makeMessy);

What happens when you run this?

2 Likes

Yeah, it took me a bit to wrap my head around callbacks. Really, the idea is very simple - pass in a function to be used at some point. In this case, myMap doesn’t really care what callback does, just that it needs to use that function. But it did take a bit for me to wrap my head around it. Writing things like this were a big part of what made it click. But don’t get frustrated.

1 Like

@JeremyLT thanks for giving me a example like this to dig into the function as argument to function stuff. Good news is I do understand your other points about how Array.prototype is used to create a method that can be used in other places, so we should use this.

When I ran the above code I get:

--*****--1--*****--
--*****--2--*****--
--*****--3--*****--
--*****--4--*****--
--*****--5--*****--
890721498721948198127498
890721498721948298127498
890721498721948398127498
890721498721948498127498
890721498721948598127498

Can you explain how this works exactly? I was going to attempt to ask a specific question about it but I think it’s better not to since it’s still strange to me.

@kevinSmith thank you. Unfortunately I haven’t been able to connect the dots on this but I’m staying at it :frowning:

Jeremy’s code is a good teaching example.

You have two functions makePretty and makeMessy. It should be clear what they do on their own.

When we invoke printOneTwoFive, we pass in those functions:

printOneToFive(makePretty);
printOneToFive(makeMessy);

Does that makes sense? We are passing in a reference for a function.

In our printOneToFive function, we accept a parameter:

function printOneToFive(callback) {
  for (let i = 1; i <= 5; i++) {
    console.log(callback(i));
  }
}

That parameter is called “callback”. When we called it the first time with this:

printOneToFive(makePretty);

We passed in a reference to the function makePretty. That gets accepted in the printOneToFive function as the parameter callback. So, at this point, callback is a reference to the function makePretty. The function printOneToFive doesn’t know and doesn’t care that it is called makePretty in the outer scope. All it knows is “I got passed a function and I stored it in ‘callback’”. It then applies that function.

2 Likes

Technically we could have used the makePretty from the global scope instead of passing it in. But that would make printOneToFive less flexible because then we’d have to have separate versions for pretty and messy. That is the strength of callbacks.

2 Likes

Gotcha so callback is replaced by makePretty and so when I see that I envision a function that combines the two as follows (this may be what I’m having trouble with):

function printOneToFive(num) {
  for (let i = 1; i <= 5; i++) {
    console.log(num(i));
return "--*****--" + num + "--*****--"
  }
}

This is the way I try to think about it but it seems to get confusing for me when I’m looking at the other exercises. What would be a better way to think about it

But we have

console.log(callback(i));

which becomes

console.log("--*****--" + i + "--*****--");

Ah ok so it becomes this?

function printOneToFive(num) {
  for (let i = 1; i <= 5; i++) {
    console.log("--*****--" + num(i) + "--*****--");
  }
}

Am I correct in thinking about functions in functions like this? It seems it can get really confusing when doing more complex functions

Why the num(i)?

We have this function

// Print the numbers 1-5 with custom formatting
function printOneToFive(callback) {
  for (let i = 1; i <= 5; i++) {
    console.log(callback(i));
  }
}

When executing this function, we can think of callback(i) as being replaced with the return value from calling callback(i).

If the callback function is

// A nice formatting function
function makePretty(num) {
  return "--*****--" + num + "--*****--";
}

then we have

function printOneToFive(callback) {
  for (let i = 1; i <= 5; i++) {
    console.log("--*****--" + i + "--*****--");
  }
}

Of course, for the last one, we no longer need the callback, it could just be:

function printOneToFive() {
  for (let i = 1; i <= 5; i++) {
    console.log("--*****--" + i + "--*****--");
  }
}

Put another way, does it make sense that these all do the same thing:

function printOneToFive1() {
  for (let i = 1; i <= 5; i++) {
    console.log("--*****--" + i + "--*****--");
  }
}

printOneToFive1();

// *****

function printOneToFive2() {
  function makePretty2(num) {
    return "--*****--" + num + "--*****--";
  }
  
  for (let i = 1; i <= 5; i++) {
    console.log(makePretty2(i));
  }
}

printOneToFive2();

// *****

function makePretty3(num) {
  return "--*****--" + num + "--*****--";
}

function printOneToFive3(callback) {
  for (let i = 1; i <= 5; i++) {
    console.log(callback(i));
  }
}

printOneToFive3(makePretty3);

The first one hard codes the stuff into the console.log. In the second one, we abstract it into a function. In the third one, it’s also abstracted into a function but instead of being defined in out printOneToFive3 function, it’s defined outside that and passed in as a parameter, aka a callback.

@JeremyLT Ok got it. So any place that has callback in it receives the part of the callback function?
@kevinSmith yeah I think so.

Am I correct in thinking about functions in functions like this? It seems it can get really confusing when doing more complex functions.


I ended up solving this with the following

// The global variable
var s = [23, 65, 98, 5];

Array.prototype.myMap = function(callback) {
  var newArray = [];
  // Only change code below this line
  for(let i = 0; i < this.length; i++) {
    newArray.push(this[i] * 2);
  }
  // Only change code above this line
  return newArray;
};


var new_s = s.myMap(function(item) {
  return item * 2;
});

console.log(new_s);

but it felt weird just redoing this part manually. I felt I wouldn’t have needed to type it out

var new_s = s.myMap(function(item) {
  return item * 2;
});

Unfortunately, I don’t think I really understand that well

Why not use the callback here?

It seems to be because I don’t understand it. What do you mean?

Your function signature has a callback function. You never use the callback function. You instead hard-coded myMap() to only work one way.

To put it another way,

var new_s = s.myMap(function(item) {
  return item * 3;
});

will fail to produce the intended results because you don’t actually use the callback function inside of myMap().

Unfortunately, I don’t understand it. Can I pay you to explain it to me via zoom?

I don’t do private video lessons, sorry.