freeCodeCamp - Functional Programming: Implement map on a Prototype - Question

Hello,
i did the exercice “fine” but i have a question. How do you “genericly” recovers the array.map(…).

In this exercice we simply use the “s” in the prototype because “s” is a global variable. But it’s not generic. It will only work with a variable named “s” so the reusability is none. So how can you recover the array (here “s”) and use it genericly, so with any array name, in the prototype ?


// the global Array
var s = [23, 65, 98, 5];

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

};

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

console.log( new_s );

link: https://beta.freecodecamp.org/en/challenges/functional-programming/implement-map-on-a-prototype

2 Likes

Hello, thanks you !
I don’t know how to use callback. And the “this.” is special in javascript. It was “easiest” to understand in Java.
I’m going to examin it.

But some thing i don’t like is it’s like it’s coming from nowhere in the “course” (the use of the callback+this).
As a studend, we have, i think, no background.

11 Likes

@camperextraordinaire What does this refers to in this.length and callback(this[x]) ??

this refers to the calling object. For example

const a = [1,2]
const b = [1]

Array.prototype.myMap = function (cb) {

   // this.length = a.length when called like a.myMap
   // this.length = b.length when called like b.myMap
   return this.length
}

4 Likes

Callbacks are functions you pass into another function. So

function someFunc(x, callback) {

   callback(x)
}

Will run the callback function for me inside someFunc. So I can call it like this for instance:

someFunc("I'm logged by the callback", console.log)// "I'm logged by the callback"

So you can think of someFunc looking like this when passed console.log

function someFunc(x, console.log) {

   console.log(x)
}

I’m not familiar with java, but according to the interwebs, this refers to the instance that the method is called on. This means in java this is referencing something internal.

In javascript, this refers to the execution context. This only means that this can refer to the instance when it’s called within itself, like in a class. But it can also bind to the calling object. Like how you see here

const a = [1,2]
const b = [1]

Array.prototype.myMap = function (cb) {

   // this.length = a.length when called like a.myMap
   // this.length = b.length when called like b.myMap
   return this.length
}

A safe(?) way to look at it is: this belongs to the caller of the function.

This isn’t always true, but in most cases it is.

2 Likes

Question: I tried a solution very similar to this but instead of using the “this” keyword, I tried using “arguments” and it didn’t work. Why doesn’t “arguments” work here? What exactly is “this” referring to in this particular scenario?

My solution was the same however I first tried to use a for…in loop like so:

  for(let i in this){ 
    newArray.push(callback(this[i]))
  }

however, this returns not only the array passed in, but also the methods in the prototype resulting in

// [46, 130, 196, 10, NaN]

A workaround could look like

  for(let i in this){ 
    if(!isNaN(i)) newArray.push(callback(this[i]))
  }

but I’m not sure if this would produce weird results in other situations.
Just some food for thought about the difference in the types of for loops.

This is because for...in iterates over all enumerable properties of the object. And in javascript, arrays are just objects with a few fancy methods attached.

If you only want to iterate over the items of the array, you have to use the for...of loop instead

It will, because if(!isNaN(i)) explicitly checks only for non-numbers.

But if you were iterating an array of objects, you’d still have issues with checking those extra properties.

If you don’t want to use a for...of loop, you have to protect like this:

from mdn:

If you only want to consider properties attached to the object itself, and not its prototypes, use getOwnPropertyNames() or perform a hasOwnProperty() check

for...in - JavaScript | MDN

for (const prop in obj) {
  if (obj.hasOwnProperty(prop)) {
    /* here we are safe */
  } 
}
2 Likes

Hey! So this worked for me, didn’t have to use much complicated solution, had a hard time grasping the concept of callback though.

// the global Array
var s = [23, 65, 98, 5];

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

};

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

Sorry guys , I really don’t know why we use callback(this[i]));

You can’t do like this, because your map should give a result depending on a callback it receives. For example what if I would like to get new array of squared values? so you need callback to make your map universal.

The callback receives a value, and returns doubled value. So we use the callback to get doubled value and push to our array that we are going to return as a result

Solution “forEach”

 // Add your code below this line
  this.forEach(function(item){
    newArray.push(callback(item))
  });
  // Add your code above this line
3 Likes

I am having a hard time with “callback” too, and sounds like a lot of people are having the same deal. Here’s my understanding:


[quote="arzish, post:12, topic:156632"]
Array.prototype.myMap = function(callback){
// Here we are defining a function that takes an input "callback". My main question here is WTF is callback? Well, let's look further down the code.
var newArray = [];

// Add your code below this line

for (let i = 0; i &lt; this.length; i++) {

newArray.push(callback(this[i]));
// OK, here's "callback" again. So we're asking our function to push a version of this[i] (a version that is modified by callback) to newArray. But still, WTF is fucking callback? (<- that, in essence is my frustration...)  Let's look further down: 

}

// Add your code above this line

return newArray;

};
// Here we are assigning stuff to new_s. That stuff is the result of myMap() with function(item) as an input. What does function(item) do? It returns item*2. So we are passing in a function that converts i to i*2 INTO the myMap() function. So when you ask yourself WTF is callback? It's an input to myMap that needs to be a function, and that function is none other than the function that we are defining below. 
var new_s = s.myMap(function(item){

return item * 2;

});
[/quote]

type or paste code here
3 Likes

My solution with forEach

this.forEach( (el) => newArray.push( callback(el) ) );
1 Like

I believe this is the expected code. The challenge should probably hint to that you should use “this” to complete the challenge.

// the global Array
var s = [23, 65, 98, 5];

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

};

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

console.log(new_s)

1 Like

Well, this was really confusing, managed to work out to use this, however, would of never have understood to use newArray.push(callback(this[i]) );

anyway, thanks to the forum, managed to work it out, but can’t say i fully understand it!

1 Like