Today we're going to implement our own .each(), .map(), and .filter() functions in javascript to learn more about for loops.

These utility functions are similar to the ones found on underscore.js and lodash.

Utility functions are convenient because it makes our code less messy and less error prone.

So instead of always writing a for loop:

var list = [1,2,3,4,5];

for (var i=0; i<list.length; i++){
	console.log(list[i]);
}

where there's a chance you might miscount the list.length by 1 or that the variable i starts from the wrong index.

We can simply create a function where it takes a list (could be an array or an object, which can be a list), and do something to every item in that list.

var list = [1,2,3,4,5];

// for each value in the list, console.log that value
_.each(list, function(value){
	console.log(value);
});

The underscore _ is just an arbitrary object so that we can attach methods such as .each() to it and call them afterwards.

Implementing .each()

Based on the above example, the .each() will take two arguments: a list and a callback function. The callback function is the thing we're going to do with each item in the list.

Why is it called a callback function? Well you can read this answer for a simple explanation.

Here's the pseudocode for .each() we're implementing:

//check if it's an array
	//if yes, loop through the array
	//for each item on the list call the callback function on that item
//else loop through the object
	//call the callback on each item in the object.

And in actual javascript code:

//declare the underscore object
var _ = {};

//add the .each() method
_.each = function(list, callback){
	if (Array.isArray(list)){
		for (var i=0; i<list.length; i++){
			callback(list[i], i, list);
		}	
	}
	else {
	  // This is how object items are iterated
      for (var key in list){
			callback(list[i], i, list);     
		}                                
	}
};

There's an interesting bit here. Notice when we call the callback function we're calling it callback(list[i], i, list);. Why do we need the three parameters: list[i], i, and list?

It's totally fine if it's just callback(list[i]) because we want to apply the callback function to the item. However, sometimes the callback function might need to access the current position of the item i and the array list itself.

So in order to make this callback function more flexible, we include these variables.  callback(list[i], i, list) will work just fine even if the callback function need just one parameter.

Here's an example code where there's only parameter in the callback:

// tellIsFruit accepts one parameter: item
var tellIsFruit = function(item){
	console.log(`${item} is a fruit`);
};

//use the.each() function

_.each (['Banana','Mango','Grapes'], tellIsFruit);

// => 'Banana is a fruit'
// => 'Mango is a fruit'
// => 'Grape is a fruit'

We can also use more variables, 3 in this case:

// tellIsFruit accepts three parameter: item, position, list
var tellIsFruit = function(item, position, list){
	if (position == 2) { // do nothing, skip Mango}
	else {
		console.log(`${item} is a fruit`);
	}
	
};

_.each (['Banana','Mango','Grapes'], tellIsFruit);

// => 'Banana is a fruit'
// => 'Grape is a fruit'

Implementing .map()

.map() is similar to .each() in that the map function also accepts 2 parameters: the list and the function to transform the list. It then iterates through the list.

But the difference is that .map() will transform the list and return an array every time.

The map function produces a new array by mapping each item in the list through a transformation function.

Assuming we have this function that makes things beautiful:

var makeBeautiful = function (item) {
	return `beautiful ${item}`;
};

If we apply the .map() to a list of items ['vase', 'TV', 'speaker'], then the map function will return an array of ['beautiful vase','beautiful TV','beautiful speaker'].

Here's the pseudocode for .map():

//create an array for storage
	// loop through the array
		//call the callback function on each item in list 
		//push the result to our array
	//return the storate array

we can build  .map() on top of the .each() we've previously written:

_.map = function (list, callback){
	var arr = [];
	_.each(list, function(item){
		arr.push(callback(item));
	});
	return arr;
}

The nice thing is .map() will handle object list as well as it is handled by .each().

So now when we apply .map() to our array of items ['vase', 'TV', 'speaker'] we get an array of beautiful items as output.

_.map (['vase', 'TV', 'speaker'], makeBeautiful);

// => ['beautiful vase', 'beautiful TV', 'beautiful speaker']

Implementing .filter()

Again, .filter() is a function that takes 2 arguments: an array and a callback. And it's going to return a new array with ONLY values that return true from the callback.

So the callback has to return a boolean, true or false.

If we want to filter odd numbers from an array. Then the callback function will have a statement like, "if current value is odd, then add to the array".

The pseudocode for .filter() are:

// create an array
  //iterate through the list
	// call the callback for each item in the list
	// if callback on the item returns true, add to the array
// return array

and the actual javascript code:

_.filter = function(list, callback){
	var arr = [];
	_.each(list, function(item){
		if (callback(item)==true){
		arr.push(item);	
		}
	});
	return arr;
}

We are going to use this .filter() function to filter a list of odd numbers.

_.filter([1,2,3,4,5,6,7,8,9], function(item){
	if (item%2==1){return true};
})

// => [1,3,5,7,9]