Reputation: 239
// Return all elements of an array that pass a truth test.
_.filter = function(collection, test) {
var result = []; //make a result variable
//iterate over the collection array using _.each
_.each(collection, function(value) {
//if conditions for test(element) = positive
if (test(value)) {
//push element into result
result.push(value);
}
});
return result;
};
Hi, I'm working on a rewriting the function of _.filter
& _.reject
from the Underscore JS library. I still get a bit confused about callback functions particularly when there are so many in the same function. I need some clarification about my thoughts and logic here; particularly about ._reject
. I am reusing my _.filter
function and implenting it in my _.reject
func.
_.reject = function(collection, test) {
return _.filter(collection, function(value) {
return !test(value);
})
};
When I have function(value) as a parameter for filter and defined it; is that replacing my test value with that functions callback? Particularly in this line -
if (test(value)) {...
does that get replaced with my callback in this case if(function(value) {return !test(value)})
Also, if I omit the return
command from my _.reject
function for _.filter
; am I just returning the function itself? Sorry - I know it's a bit bizarre since my code works as far as I know but it was really more of an effort of trying things out then actually understanding it logically. I just get very confused on what happens when I calling the callback function in filter from my reject function
Upvotes: 0
Views: 393
Reputation: 13709
In JavaScript, everything is an object—including functions. When you write a function expression (as they're called) like this:
const foo = function() {
console.log('This function prints this message!');
};
foo
now contains a reference to the function that prints the message. We can call it like this:
foo();
…which runs the code and prints the message. You can pass foo
around like any other value, including as a parameter to other functions. Think of it like saving a set of instructions for doing something: you're telling the computer "foo
contains the code that, when run, prints a message."
In your example, the function expression that you're passing as the second argument to _.filter
is an object:
function(value) {
return !test(value);
}
You're saying "Pass this function—which takes a value, calls test
with it, negates the result, and returns it—to my _.filter
function." _.filter
knows to call that function to filter out values.
Programming is full of these sorts of patterns: the goal isn't to look at what's happening all the way down, it's to understand that _.filter
accepts a second parameter that's a function that says "If you give me a value, I'll tell you whether to keep it." And in your code, you're passing it a function that does just that—but it also calls another function (test
) that your user passed in. Chains of function calls can be long: hundreds or thousands of functions calling other functions.
In your case, it looks like your code is correct. _.filter
says "Give me an array of data and a function. I'll call that function for each value in the array, and it'll return me whether to keep it." You're making a function that says "Give me an array of data and a function. I'll call that function for each value in the array, and it'll return me whether not to keep it." To do this, you're just inverting what _.filter
wants to know: instead of whether to keep a record, you want to know whether to eliminate it.
So your code gives the user's array and a function to _.filter
just like it wants. The function gets called with each element of the array. _.filter
wants to know whether to keep the item. You're going to call test
with the item that _.filter
asks you about. But if the user's function returns true
, we want to eliminate the element, rather than keep it, so we negate that (with !
) and return the value. You're then returning the result of _.filter
.
To clarify about return
: the return
keyword tells the function calling your function what you want to "give back". So when you return !test(value)
, you're telling whatever called your function the value of !test(value)
(in this case, that's _.filter
). If you didn't use return
, you wouldn't be giving anything back to the code that called your function. If the user wants to know what the array looks like after the elements have been rejected, and your function didn't return
anything, then your function isn't very useful!
Upvotes: 1