forEach query on Implementing the filter Method on a Prototype

Tell us what’s happening:

I think my logic is sound:

  1. I have iterated through s (using the this keyword).
  2. and indicated that the parameter callback should be implemented on each element of this
    3.If such implementation were to equal one then that element should be pushed onto the empty array newArray
  3. Return newArray

What am I missing?

Your code so far


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

Array.prototype.myFilter = function(callback){
  var newArray = [];
  // Add your code below this line
 this.forEach(function(callback){
    if(this === 1){
      newArray.push(this);
    }
  })
  // Add your code above this line
  return newArray;

};

var new_s = s.myFilter(function(item){
  return item % 2 === 1;
});

Your browser information:

User Agent is: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.110 Safari/537.36.

Link to the challenge:
https://learn.freecodecamp.org/javascript-algorithms-and-data-structures/functional-programming/implement-the-filter-method-on-a-prototype/

this.forEach(function(callback){  // if this is an array here
  if(this === 1){  // how can this equal 1 here on next line?
   newArray.push(this); 
  } 
})

Are you sure you did this?

Stated another way…

From MDN
The filter() method creates a new array with all elements that pass the test implemented by the provided function.

Did you test all the elements to see if they pass the test implemented by the callback? Each element is to be tested by the callback function provided. Those that test true are put in the new array and those that test false are not.


EDIT:
in the test case this is the array [23,65,98,5]

A trace through your logic would be something like this

does 23 pass the test?
Yes, put 23 in newArray
does 65 pass the test?
Yes, put 65 in newArray
does 98 pass the test?
No, 98 does not go in newArray
does 5 pass the test?
Yes, put 5 in newArray

return newArray

That would indicate iteration.

  • You have chosen to use .forEach to iterate through the array but you aren’t using forEach correctly.
  • Was there another way suggested in the challenge to iterate through array that might be more familiar?
  • If you are intent on using forEach do you know what parameters are passed by forEach? callback is not one of those.

this here refers to an array. so to iterate through its each element, call this.forEach

Originally, I tried to use a for loop, but I changed my mind because I wanted to explore with forEach. However, my time with the for loop had the same amount of success. I’m thinking that my problem here is that I haven’t established a boolean correctly, but I’m not certain where my mistake is.

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

};

You are not using the callback function anywhere inside your myFIlter. It is the result of the callback function which you need to compare against the value true.

Also, note that this[i] = true is not a comparison, because = is the assignment operator.

I thought I was approaching this correctly, but now I’m seeing some aspects that have faulty logic.

  1. It not longer makes sense to me that the callback parameter exerted on an element should be boolean. I don’t know why that would be.
  2. It doesn’t make sense that I would push the elements exerted on by callback into newArray.

I’m not sure if these points are valid, but if they are then is it one of them or both? If none of my concerns are valid then where do I need to start looking to correct my errors?

var s = [23, 65, 98, 5];

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

};

var new_s = s.myFilter(function(item){
  return item % 2 === 1;
});

Looks like you’re trying to iterate over a callback, which doesn’t make sense since callback is a function. Think again about what filter is. It’s a type of function that takes another function (so-called callback) as an argument. It calls that callback function for every item in the calling array, passing the current item in the calling array as an argument. And each time callback(item) evaluates to a truthy value, filter adds that item to the new array. In the end, it returns that new array.

Also, you need to reference the calling array somehow in your code, which presently you’re not doing.

@bananahair, look at these 2 examples and try to implement with forEach():

const reducePretendsToBeFilter = (arr, callback) =>  arr.reduce((a, b) => callback(b) ? a.concat(b) : a, []);

const mapPretendsToBeFilter = (arr, callback) => arr.map(i => callback(i) ? i : []).flat();

Good luck!

I am not passing and I was wondering if you might explain where I’m messing up.
I have a calling array, which I iterate through and I’m calling the callback function on each current item (arr[I]) and pushing it to newArray when it evaluates to true.

I mean, this is what I think I’m doing. Where am I misguided in my thinking?


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


//type of function that takes another function as an argument
Array.prototype.myFilter = function(arr, callback){
  var newArray = [];
  // function calls that function (callback) for every item in the calling array
for(let i = 0;arr.length;i++){
  if(callback(arr[i])){
    //item is pushed to newArray if it is true (i.e. = item % 2 === 1)
    newArray.push(arr[i]);
  }
}
  
  // Passing the current item in the calling array as an argument
  //if that evaluates to a truthy value it pushes it into the empty array
  return newArray;

};

var new_s = s.myFilter(function(item){
  return item % 2 === 1;
});

Array.prototype.myFilter = function(arr, callback){ ... }

You’ve added a new parameter to the function: arr. You shouldn’t do that. Notice that when myFilter is called at the bottom of the challenge, it is only passed 1 argument: the callback function. So, you must implement myFilter in such a way that it works with just 1 argument.

Inside the parenthesis of the for loop, the condition that determine if the loop continues or if it stops it’s just arr.length, it must be something that is either true (the loop continue) or false (the loop stops)

I’m running out of ideas. I understand callback is a function and I’ve been trying to keep that in mind, but I’m worried that I’m using it in a very non-function way. ( I worry that I’m doing something that creates too large a stack to process)

Below I explain more in comments within my code. I’m not passing and looking for somebody to give me a nudge in a different direction.


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

Array.prototype.myFilter = function(callback){
  var newArray = [];
  //Here I intend to call callback on each element in the for loop and have that equal out true(what I'm assuming can also be written as "1" considering the function at the bottom)
  for(let i = 0;callback[i] === 1; i++){
//if the call on an element equals 1 then I push it into newArray and this seems as if it should work, but it is not.
    if(callback[i] === 1){
      newArray.push(i);
    }
  }
  
  // Add your code above this line
  return newArray;

};

var new_s = s.myFilter(function(item){
  return item % 2 === 1;
});

callback is not an array, it is a function so you can’t use it in that way. (you can’t use it as callback[i]), but you can as a function callback()

you can reference the array you are filtering using this keyword.

For the for loop, as soon as the second statement inside the parenthesis is false the loop stops, so if you are iterating over an array you may want to do i < array.length, till this is true the loop keep going

the callback returns true or false, you can check if you can use 1 trying to write console.log( 1 === true), if this is true you can use also that one, but it is false, so you better evalutare the result of the callback with true

I really feel like this is the answer, but it’s not passing. What am I doing wrong? I’ve included comments below. Where is my logic missing the point?

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

Array.prototype.myFilter = function(callback){
  var newArray = [];
  // Using this to stand in for the array to loop through
  for(let i = 0;i < this.length; i++){
//Calling callback on the iterated elements that, when run through callback, are true.
    if(callback(this[i] === true)){
//pushing those elements that are true onto the empty array container
      newArray.push(this[i]);
    }
  }
  
  // Add your code above this line
  return newArray;

};

var new_s = s.myFilter(function(item){
  return item % 2 === 1;
});

You’re almost there! The only problem now is in the condition of your if statement. Filter is supposed to pass every element through a callback.

Consider this line, consider carefully the parenthesis. Where is the comparison? You are not passing this[i] inside the function, you are passing this[i] === true

Also, this comment:

Calling callback on the iterated elements that, when run through callback, are true.

Is not true, you are calling callback on all elements, and then keeping only those that give true

Okay, I solved it and I was wondering if y’all might check my logic below.


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

Array.prototype.myFilter = function(callback){

  //create empty array

  var newArray = [];

  // iterate through array, using this object to stand in for empty array and prevent mutation of global variable

 for(var i = 0; i < this.length; i++){

   //use if statement to determine if calling of function on particular element in array is true

   if(callback(this[i])===true){

/*my problem before was that there was no comparison...in other words, I wasn't indicating that this[i] needs to be called on by the function AND THAT must have a value of true.  Before I was including this[i]===true as a single line that is having a function called on it, which makes so sense since true should be the resulting value that acts as the gatekeeper for entrance into the newArray array.*/


     newArray.push(this[i]);
   }
  
   
   
 }
 return newArray;
  // Add your code above this line
 
 

};

var new_s = s.myFilter(function(item){
  return item % 2 === 1;
});

Your second comment: this is not the empty array, it is the array on which the function is applied: in s.myFunction(), s is this. It is not true that it doesn’t manipulate the original array, but in this case your function is not changing anything on this. If you need to work directly on this, to avoid changing It you need to copy it in a local variable inside the function.

Just a note on the if statement, it executes if what is inside the parenthesis is true, as the callback function already returns true or false you can avoid adding the comparison callback(this[i]) === true and just use callback(this[i])

If you need the if statement to execute when the function is false you can invert the value with !callback(this[i])

If your function returns anything else than there you absolutely need the comparison

And just using callback(this[i]) will make your filter act like the real filter which just checks for truthy/falsy.

1 Like

Oh, and while it seems you gave up on Array.forEach(), you can absolutely use it instead of the for loop if you want:

this.forEach(function (n) {
    if (callback(n)) {
      newArray.push(n);
    }
  });
1 Like