This post will work through ‘Seek and Destroy’, one of freeCodeCamp‘s basic algorithm scripting challenges. This challenge will help us introduce the Arguments object and callback functions.
The Seek and Destroy challenge states that ‘provided with an initial array (the first argument in the destroyer function), followed by one or more arguments’ we need to write a function that will remove the values of all the arguments given after the initial array, from the initial array.
Sounds confusing, I know… Let’s visualize it to clear things up.
1 2 3 4 5 6 7 8 |
function destroyer(arr){ //write a function that can be called //with any number of arguments provided //(see destroyer call below) //and remove those arguments from the initial array(arr) } destroyer(arr, value1, value2, value3, value4); |
One of the major problems we have lies with ‘followed by one or more arguments’… If we don’t know how many arguments there will be, how do we write a function to handle them?
The answer to that comes in the form of the Arguments object. JavaScript provides a local variable ‘arguments’ that acts like an array with an element for each argument passed to the function. You access the arguments just like you would an element of any other array like so:
1 2 |
arguments[0] //contains the initial array arguments[1] //contains the first value to delete from the initial array |
The arguments object makes solving this algorithm challenge much easier. Looking forward at ways to solve this problem, we need to a) access the arguments we need to delete from the initial array and b) somehow remove those arguments from the array.
Storing arguments for easy access
The first thing we’ll do is create a new array and store all the arguments (other than the initial array) in it.
1 2 3 4 5 |
var argArr = []; for (var i = 1; i < arguments.length; i++){ argArr.push(arguments[i]); } |
As you can see, arguments can be treated like any other array… Here, we used the length property and looped through arguments (starting at element 1 so as to avoid the initial array, which will be passed in as the first argument, or arguments[0]). Setting it up this way will handle any number of arguments passed to the destroyer function.
The push() method in JavaScript is used to ‘push’ new elements on to the end of the calling array.
Tools we’ll need to remove arguments from the array
In order to remove the arguments from the initial array, we will use the filter() method. The filter method introduces a concept we haven’t talked about here at CrookedCode: the callback function.
A Quick note on functions in JavaScript
The power of functions, and what they allow you to do, are core to successful JavaScript programming. Functions can be passed to and returned from other functions. They can also be stored as variables.
A function that accepts another function as an argument is called a higher-order function, whereas, the function that is passed as the argument is called a callback function. The Eloquent JavaScript chapter on functions is a great tutorial on the use of functions in JavaScript.
Eloquent JavaScript also devotes an entire chapter to higher-order functions. I highly recommend reading and working through the examples in both of these chapters. If you’re looking for something a little quicker, JavaScriptissexy.com has an excellent article on understanding callbacks and higher order functions.
The filter() method accepts a callback function and performs that callback on every element in the calling array. If the callback returns true for a given element, that element is kept. If the callback returns false, obviously, that element is not kept.
As stated above, filter() calls the callback function on every element of the calling array, but it does not mutate that array. Therefore, you must save the kept elements as a new array.
The one final tool we’ll need before we try to solve this algorithm is the array.indexOf() method. indexOf() will return the first index at which a given value is found. If the given value is not found, indexOf() returns -1.
Putting it all together…. (finally)
We’ve already created argArr[] to hold the values that we need to delete from the initial array. We now need to write a callback function for filter() that will return true if we want the element to stay and false if we want to delete that element.
We know that indexOf() will return -1 if a given value is not found. We also know that we want to keep elements of the initial array that aren’t found in argArr[]. So, for each element of the initial array, lets call argArr.indexOf(), and return true for values of -1. Therefore, we’ll be returning true for (and keeping) values that aren’t in argArr[].
Like so:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
function destroyer(arr) { // create array to store arguments to be deleted var argArr = []; //cycle through the arguments object and store in argArr for (var i = 1; i < arguments.length; i++){ argArr.push(arguments[i]); } //filter out values found in argArr //if value is not found, -1 will be returned from indexOf() //therefore the callback will return true and the element will be kept arr = arr.filter(function(val){ return argArr.indexOf(val) === -1; }); //return new array return arr; } |
Wow… This post covered a bunch of stuff we haven’t previously gone over here at CrookedCode, hopefully this helped straighten out the code for you. See you next time…
-Jeremy