Loop-a-palooza

Revisiting loops, callbacks, and higher order functions
Higher Order Functions Review
Explaining Each
Expanding Each
Loops on Loops on Loops
Overview


Higher ORder Functions
Review

HIgher Order functions
A higher order function is a function that either:
-
Takes a function as an argument. -
Returns a function to be used at a later time.
This week we are focused on the first one.

each
Allow me to reintroduce myself, my name is each.
var each = function(collection, callback){
// loops through the collection
for (var i = 0; i < collection.length; i++){
// passes each element inside of collection
// to the callback
callback(collection[i])
}
};

each
each in action
var each = function(collection, callback){
for (var i = 0; i < collection.length; i++){
// passing each array element into our callback
callback(collection[i]);
}
}
var bestSentence = ['I', 'love', 'javascript'];
each(bestSentence, function(word){
console.log(word.toUpperCase());
});
// 'I'
// 'LOVE'
// 'JAVASCRIPT'The anonymous function corresponds to the callback parameter we specify in each.
The `word` parameter corresponds with the argument being passed into our callback.

each
What happens when our callback returns?
var each = function(collection, callback){
for(var i = 0; i < collection.length; i++){
callback(collection[i]);
}
}
var numbers = [1, 2, 3, 4, 5];
each(numbers, function(element){
// returning instead of console.logging
return element;
});var each = function(collection, callback){
for(var i = 0; i < collection.length; i++){
console.log(callback(collection[i]));
}
}
var numbers = [1, 2, 3, 4, 5];
each(numbers, function(element){
// returning instead of console.logging
return element;
});Let's throw a console.log inside of our `each` so that we can see what's being returned.

each
what is the purpose of each then?
Definition: The Each function provides its callback access to each element inside of a collection.
That's it.
No really, that's it.

Multby2
multBy2 takes an array of numbers and returns a new array with each element multiplied by 2
var multBy2 = function(array) {
var results = [];
for (var i = 0; i < array.length; i++){
results.push(array[i] * 2);
}
return results;
};Let's replace our for-loop with our 'each' function
var multBy2 = function(numbers) {
var results = [];
each(numbers, function(number){
results.push(number * 2);
});
return results;
};Our `ea` function makes this code more expressive and clean.

Multby2
multBy2 in depth:
var multBy2 = function(numbers) {
var results = [];
each(numbers, function(number){
results.push(number * 2);
});
return results;
};The callback has access to the `results` array in its parent scope
Thanks to each, the callback also has access to each number in the `numbers` array.

Multby2
multBy2 in action:
var multBy2 = function(numbers) {
var results = [];
each(numbers, function(number){
results.push(number * 2);
});
return results;
};
var nums = [1, 2, 3, 4, 5];
var numsMult2 = multBy2(nums);
Let's throw this in the console and see what we get.

Expanding each
Expanding the functionality of our loop function

Expanding each
Our current loop function
var each = function(collection, callback){
for (var i = 0; i < collection.length; i++){
callback(collection[i]);
}
};
We've been building functions where loop can only take an array, but what about objects?

Expanding each
Expanded to work with objects or arrays
var each = function(collection, callback){
if (Array.isArray(collection){
for (var i = 0; i < collection.length; i++){
callback(collection[i]);
}
} else if (typeof collection === 'object'){
for (var key in collection){
callback(collection[key]);
}
}
};
Expanding each
New loop in action
var obj = {name: 'Albrey', favoriteColor: 'blue'};
each(obj, function(value){
console.log(value);
});
// 'Albrey', 'blue'
Expanding each
But that's not it...
var obj = {name: 'Albrey', favoriteColor: 'blue'};
each(obj, function(value){
console.log(value);
});
// 'Albrey', 'blue'When do we ever just deal with values?
Let's expand our loop even further to support passing keys/indexes to our callback.

Expanding each
Expanding loop even further
var each = function(collection, callback){
if (Array.isArray(collection)){
for (var i = 0; i < collection.length; i++){
callback(collection[i]);
}
} else if (typeof collection === 'object'){
for (var key in collection){
callback(collection[key]);
}
}
};Passing the current key/index to our callback.
var each = function(collection, callback){
if (Array.isArray(collection)){
for (var i = 0; i < collection.length; i++){
callback(collection[i], i);
}
} else if (typeof collection === 'object'){
for (var key in collection){
callback(collection[key], key);
}
}
};
Expanding each
Expanded loop in action
var obj = {name: 'Albrey', favoriteColor: 'blue'};
each(obj, function(value, key){
console.log('this is the value:', value);
console.log('this is the key:', key);
});
// "this is the value: Albrey"
// "this is the key: name"
// "this is the value: blue"
// "this is the key: favoriteColor"Specifying `key` parameter in our callback.

Expanding each
Can we reference key and not value?
var obj = {name: 'Albrey', favoriteColor: 'blue'};
each(obj, function(key){
console.log('we only want the key', key);
});
// "we only want the key: Albrey"
// "we only want the key: blue" We must insert 2 parameters in order to access the key.
var obj = {name: 'Albrey', favoriteColor: 'blue'};
each(obj, function(value, key){
console.log('we only want the key', key);
});
// "we only want the key: name"
// "we only want the key: favoriteColor" 
loops on loops
Because sometimes one is just not enough.

NEsted Data
var person = {
name: "Jon Tippens",
greatestFear: "Those frozen biscuit things.",
dateUsedAgainstHim: "2/02/1997",
};
for (var characteristic in person){
console.log(person[characteristic]);
};
// 'Jon Tippens'
// "Those frozen biscuit things."
// "2/02/1997"This data structure is not nested in another datastructure

NEsted Data
var people = [{
name: "Jon Tippens",
greatestFear: "Those frozen biscuit things.",
dateUsedAgainstHim: "2/02/1997",
}, {
name: "Albrey Brown",
greatestFear: "Brain aneurysm.",
dateUsedAgainstHim: "03/30/1991",
}];Our original person object is nested in the 'people' array
var jon = {
name: "Jon Tippens",
greatestFear: "Those frozen biscuit things.",
dateUsedAgainstHim: "2/02/1997",
};
var albrey = {
name: "Albrey Brown",
greatestFear: "Brain aneurysm.",
dateUsedAgainstHim: "03/30/1991",
};
var people = [jon, albrey]Let's make this look more palatable
Our two persons are nested in our people array.

Nested Data
How do we loop through each object?
var people = [jon, albrey]
for (var i = 0; i < people.length; i++){
console.log(people[i]);
};
// { name: "Jon Tippens", greatestF...}
// { name: "Albrey Brown", greatestF...}Looping through the `people` array allows us access to each `person`.
We need a second for-loop to loop through the characteristics in our persons

Double For Loop
Add another for loop
var people = [jon, albrey]
for (var i = 0; i < people.length; i++){
var person = people[i];
for(var characteristic in person){
console.log(person[characteristic]);
}
}
// Jon Tippens
// Those frozen biscuit thingies
// 2/02/1997
// Albrey Brown
// Brain aneurysm
// 03/30/1991instead of `person`, we can access people[i]
var people = [jon, albrey]
for (var i = 0; i < people.length; i++){
for(var characteristic in people[i]){
console.log(person[characteristic]);
}
}
// Jon Tippens
// Those frozen biscuit thingies
// 2/02/1997
// Albrey Brown
// Brain aneurysm
// 03/30/1991
Double For Loop
Make Sense?
GReat!
Let's take it up a notch

Double Loop
Anything you can do I can do better...
var people = [jon, albrey]
for (var i = 0; i < people.length; i++){
for(var characteristic in person){
console.log(person[characteristic];
}
}Remember, we're supposed to be ridding the world of for-loops
How can we use our `loop function to achieve the same thing?
var people = [jon, albrey]
// loop through the people array
loop(people, function(person){;
for(var characteristic in person){
console.log(person[characteristic]);
}
});var people = [jon, albrey]
// loop through the people array
loop(people, function(person){;
loop(person, function(characteristic){
console.log(characteristic);
});
});
// Jon Tippens
// Those frozen biscuit thingies
// 2/02/1997
// Albrey Brown
// Brain aneurysm
// 03/30/1991First, let's replace our first for-loop with a `loop`
Then, we can replace our for-in loop with a `loop` function

Double Loop
Break it down now
var people = [jon, albrey]
loop(people, function(person){;
console.log(person)
});
// { name: "Jon Tippens", greatestF...}
// { name: "Albrey Brown", greatestF...}Looping through the `people` array allows us access to each `person`.
var people = [jon, albrey]
// loop through the people array
loop(people, function(person){;
loop(person, function(characteristic){
console.log(characteristic);
});
});
// Jon Tippens
// Those frozen biscuit thingies
// 2/02/1997
// Albrey Brown
// Brain aneurysm
// 03/30/1991We can then pass each `person` to our loop, and console.log

Double Loop
one more time
var people = [jon, albrey]
for (var i = 0; i < people.length; i++){
for(var characteristic in person){
console.log(person[characteristic];
}
}Remember, we're supposed to be ridding the world of for-loops
How can we use our `loop function to achieve the same thing?
var people = [jon, albrey]
// loop through the people array
loop(people, function(person){;
for(var characteristic in person){
console.log(person[characteristic]);
}
});var people = [jon, albrey]
// loop through the people array
loop(people, function(person){;
loop(person, function(characteristic){
console.log(characteristic);
});
});
// Jon Tippens
// Those frozen biscuit thingies
// 2/02/1997
// Albrey Brown
// Brain aneurysm
// 03/30/1991First, let's replace our first for-loop with a `loop`
Then, we can replace our for-in loop with a `loop` function

Exercises
COntinue working with our partner on the Infinite Loops exercises.
You can find them at telegraphprep.github.io/part3.html
Infinite Loops
By telegraphprep
Infinite Loops
Loops, callbacks, and higher order functions.
- 1,604