JavaScript Fundamentals:
Functional
Slides:
https://slides.com/hrjr/telegraphPrepWeek3
Classwork:
https://github.com/RebootJeff/jsFunctions
https://github.com/telegraphPrep/week3
Curriculum by:
Bianca Gandolfo, Jeff Lee, Preston Parry
![](https://s3.amazonaws.com/media-p.slid.es/uploads/biancagandolfo/images/677247/standard-long-dropshadow_dark_850x250.png)
Hoisting
Scope
Closures
Callbacks
Higher-Order Functions
Who are you?
- Have a good understanding of
JS arrays, objects, and loops. - Have a basic understanding of
JS functions. - Want to solidify fundamentals
- Seek more practice
Class Format
- Ask questions (between slides)
- Answer my questions
- Show thumbs
- Ask for help during exercises
Hello, world
- Name
- Something surprising that most people in this room wouldn't know about you
- How long you've been coding
- A dance move
Intro
- We're here to make you highly effective engineers, not to give you a comfortable experience
- A bumpy road will get you there more quickly
Expectations
- Using Google and StackOverflow is a part of your job as an engineer. Get used to using these resources now.
Google/ StackOverflow
- The number of times you logged something to the console and got a different result.
- Your ability to explain exactly what every single word and piece of punctuation is doing once you have the expected output.
Success Metrics
1. Experiment. Try new things like crazy. See what you get.
2. Sit down and explain things super methodically once you have the right answer.
Success, Revisited
WE HOPE YOU CHOOSE TO JOIN US ON THIS JOURNEY!
Review:
Basics of Functions
and Hoisting
Function Anatomy
Thumbs?
![](https://s3.amazonaws.com/media-p.slid.es/uploads/304195/images/1533071/Screen_Shot_2015-06-28_at_10.39.08_AM.png)
2 ways to make function vars
var spitASickRhyme = function() {
console.log('I\'m in the pursuit of Princess Peach and I know');
console.log('When I think I\'ve won, she\'s in another castle');
};
// function EXPRESSION <(•_•^) and (v•_•)> function DECLARATION
function spitASickRhyme() {
console.log('I\'m in the pursuit of Princess Peach and I know');
console.log('When I think I\'ve won, she\'s in another castle');
}
Hoisting- Your code and the computer
// function expression
var haveFun = function() {};
// function declaration
function learnJS() {}
// variable declaration
// and assignment
var greeting = 'hello, world';
if(false) {
var jeffIsAmazing = 'duh';
}
// declarations
var haveFun;
function learnJS() {}
var greeting;
var jeffIsAmazing;
Your code:
How the computer reads it:
// definitions
// and assignments
haveFun = function() {};
greeting = 'hello, world';
if(false) {
jeffIsAmazing = 'duh';
}
console.log(jeffIsAmazing);
// will log `undefined`
Hoisting
Key Takeaway:
Don't try to access a variable before you've assigned it!
Things don't exist in the way you expect them to before you've actually written out the code for them.
Variables- values & references
Let's talk about links and webpages
Let's create a link to my favorite webpage:
You'd probably expect them all to take us to the exact same webpage. And you'd be right!
Let's imagine, for the sake of example, that they keep a live tally of members on their site, and that right now they have 12,000 members.
Let's talk about links and webpages
Let's create a link to my favorite webpage:
Since you're a good and involved citizen, and want to support the freedom and capability people gain when they bike, you join the SFBC!
(yay!!)
obviously, I'm not exactly a neutral source here :)
Let's talk about links and webpages
Let's create a link to my favorite webpage:
When we go to check out the membership count after this update, would we expect to see 12,001 members listed on the site no matter which link we click?
Of course!
And you'd be right, again.
Let's talk about links and webpages
Let's create a link to my favorite webpage:
Now let's say you're a data geek and decide that having data on your cycling sounds fun. So let's change the link we currently have for "them" to point to strava.com (an awesome bike tracking app).
Let's click the link just to see the change.
Let's talk about links and webpages
Let's create a link to my favorite webpage:
After changing the link saved in "them", do we expect our other links to still take us to the Bike Coalition?
Of course!
And would we expect to be able to make changes to the strava.com website without impacting the Bike Coalition's website?
Of course again!
Let's talk about links and webpages
"This is obvious. Why do we need so many slides on something we all know so well already?"
Because this is exactly how Arrays and Objects work in JS.
When you save an array or object into a variable, what that variable actually gets is a link to a position on our computer's memory that stores the array.
In the case of our webpage, the link takes us to a web address. In the case of our array, the link takes us to a hard drive address*.
*technically, a memory address, but that's way more specific than we need to care about now.
Let's talk about links and webpages
Let's go through and turn our SF Bike Coalition example into code so you can see just how effective this analogy is.
Let's talk about links and webpages
Let's create a link to my favorite webpage:
You'd probably expect them all to take us to the exact same webpage. And you'd be right!
Let's imagine, for the sake of example, that they keep a live tally of members on their site, and that right now they have 12,000 members.
var sfbc = {members: 12000};
var them = sfbc;
var several = sfbc;
var samePage = sfbc;
console.log(them); //{members: 12000}
console.log(several); //{members: 12000}
console.log(samePage); //{members: 12000}
Let's talk about links and webpages
Let's create a link to my favorite webpage:
Since you're a good and involved citizen, and want to support the freedom and capability people gain when they bike, you join the SFBC!
var sfbc = {members: 12000};
var them = sfbc;
var several = sfbc;
var samePage = sfbc;
sfbc.members += 1; // smiley :)
Let's talk about links and webpages
Let's create a link to my favorite webpage:
When we go to check out the membership count after this update, would we expect to see 12,001 members listed on the site?
Of course!
No matter which link we clicked?
var sfbc = {members: 12000};
var them = sfbc;
var several = sfbc;
var samePage = sfbc;
sfbc.members += 1;
console.log(sfbc); //{members: 12001}
console.log(them); //{members: 12001}
console.log(several); //{members: 12001}
console.log(samePage); //{members: 12001}
Remember each of these variables is nothing more than a link pointing to the same webpage, or the same position in memory.
Let's talk about links and webpages
Let's create a link to my favorite webpage:
Now let's say you're a data geek and decide that having data on your cycling sounds fun. So let's change the link we currently have for "them" to point to strava.com (an awesome bike tracking app).
Let's click the link just to see the change.
var sfbc = {members: 12000};
var them = sfbc;
var several = sfbc;
var samePage = sfbc;
them = {name: 'Strava'};
console.log(them); //{name: 'Strava'}
Let's talk about links and webpages
Let's create a link to my favorite webpage:
After changing the link saved in "them", do we expect our other links to still take us to the Bike Coalition?
Of course!
And would we expect to be able to make changes to the strava.com website without impacting the Bike Coalition's website?
Of course!
var sfbc = {members: 12000};
var them = sfbc;
var several = sfbc;
var samePage = sfbc;
console.log(sfbc); //{members: 12001}
console.log(several); //{members: 12001}
console.log(samePage); //{members: 12001}
them.friends = 15;
console.log(them);
//{name: 'Strava',
// friends: 15}
console.log(sfbc); //{members: 12001}
console.log(several); //{members: 12001}
console.log(samePage); //{members: 12001}
Let's talk about links and webpages
"This is obvious. Why do we need so many slides on something we all know so well already?"
Because this is exactly how Arrays and Objects work in JS.
When you save an array or object into a variable, what that variable actually gets is a link to a position on our computer's memory that stores the array.
In the case of our webpage, the link takes us to a web address. In the case of our array, the link takes us to a hard drive address.
Values work as you have expected all along
- Note that variables that are equal to a "Primitive" value (number, boolean, string, etc.) work as you expect them to.
- You get that actual value itself, not a reference to something.
- If you have two variables equal to 8, and you change one of those variables, it will not have any effect on the other variable.
Only objects and arrays are passed by reference
- Technically, functions are passed by reference too, since arrays and functions are implemented as objects by the JavaScript internals.
- I say this mostly as a warmup for later in the week when it's useful to know that functions are just fancy objects.
Scope
- Scope determines what variables are available for you to use at any given point in your program.
- Scope allows you to 'hide' variables in local scopes, or make them available to everyone in global scope.
What is scope and why does it matter?
- To have multiple for loops all using i as their iterator
- Avoid polluting the global namespace
- Say you're Facebook, and you have millions of lines of code. You're probably going to use the variable 'likes' to mean different things in different parts of your code.
- Closures!! We'll get to this shortly. It's pretty cool.
Why would we want to hide something in local scope?
- There's only one way to create local scope: inside a function body.
- Each function body has it's own local scope.
- This is the only way to create local scope.
- Nothing else creates local scope. Only function bodies.
How do we create local scope where we can hide a variable?
- Local
- Global
- Nested Scopes
- Precedence
SCOPE-RELATED CONCEPTS
Local Scope
var func = function(){
var local = true;
};
console.log(local);
ReferenceError: local is not defined
- What does local scope mean?
- It simply means that variables defined in here are 'hidden' from the rest of the program.
- That is, they only exist in this scope.
Local Scope
var global;
var func = function(){
var local = true;
};
console.log(local);
console.log(global); //undefined
![](https://s3.amazonaws.com/media-p.slid.es/uploads/304195/images/1357698/Screen_Shot_2015-05-08_at_9.47.30_AM.png)
- A variable will be undefined if it exists in that scope but hasn't been defined yet.
- A variable will throw this breaking ReferenceError if it does not exist in that scope.
Global scope
- Global scope is for variables you want to be broadly accessible.
- Avoid putting things here unless you have to.
var x = 'global!';
//inside a function
function addToGlobalScope(){
y = 'global here, too!';
}
//inside a function
function addToGlobalScope(){
y = 'global here, too!';
}
Global Scope
REMEMBER: y is not declared until addToGlobalScope is called.
- Using the keyword var creates a variable and assigns it to the current scope.
- Not using the var keyword puts it in the global scope, no matter where it is in your program.
var x = 'global!';
//inside a function
function addToGlobalScope(){
y = 'global here, too!';
var z = 'using var inside a
function body makes this local';
}
Global vs. Local Scope
- Using the keyword var creates a variable and assigns it to the current scope.
- Not using the var keyword puts it in the global scope.
//inside a function
function addToGlobalScope(){
y = 'global here, too!';
}
Keyword Var
- Always use the var keyword to create new variables. Funky, unexpected things happen when you don't.
- Plus, it just makes your code easier to read.
- This is one of those areas of engineering where just following a simple rule (always use the var keyword when declaring a new variable) will save you a lot of effort and future pain.
- You can spend time learning more if you want, or you can just always use the keyword var.
//inside a function
function addToGlobalScope(){
y = 'global here!';
window.a = 'window is an object
in the global scope.';
}
Global scope through window object
- window is nothing more than an object that sits in the global scope in all browsers.
- Properties on objects have the same scoping as the objects themselves.
Top secret security clearance review
- When you have no security clearance, you're stuck looking at only public information.
- When you have Secret clearance, you check that information first before checking the public info.
- And when you have Super Top Secret clearance, you check Super Top Secret info first before checking Secret, before checking public.
security clearance Example
var aliensExist = false; //global scope
console.log(aliensExist); //false
var secretClearance = function() {
var aliensExist = 'only sort of...';
console.log(aliensExist); //'only sort of...'
};
secretClearance();
var superTopSecretClerance = function() {
var aliensExist = 'They totally do';
console.log(aliensExist) //'They totally do'
};
superTopSecretClearance();
Ingredient of the day example
var globalRequirement = 'pies';
var cookingBonanza = function(ingredient) {
console.log('I am cooking ' + globalRequirement + ' with ' + ingredient);
};
cookingBonanza('collard greens');
//'I am cooking pies with guacamole'
Don't worry, I don't get to do much of the cooking in my house.
var globalRequirement = 'pies';
var cookingBonanza = function(ingredient) {
var obstinateChef = function() {
var ingredient = 'guacamole'; //we are 'masking' ingredient here
//we can still access the global globalRequirement variable
console.log('I am cooking ' + globalRequirement + ' with ' + ingredient);
};
console.log('I am cooking ' + globalRequirement + ' with ' + ingredient);
};
cookingBonanza('collard greens');
var globalRequirement = 'pies';
var cookingBonanza = function(ingredient) {
var obstinateChef = function() {
var ingredient = 'guacamole'; //we are 'masking' ingredient here
//we can still access the global globalRequirement variable
console.log('I am cooking ' + globalRequirement + ' with ' + ingredient);
};
obstinateChef();
//notice that our change to ingredient (using the var keyword!) doesn't
//ever have to leave it's scope. the ingredient variable
//inside obstinateChef exists only in that scope.
console.log('I am cooking ' + globalRequirement + ' with ' + ingredient);
};
cookingBonanza('collard greens');
//'I am cooking pies with guacamole'
//'I am cooking pies with collard greens'
creating scopes
When are scopes actually created?
- Each invocation of a function runs completely separately from all other invocations of that function.
- "Execution scopes" are created each time you invoke a function.
- Variables are always hoisted inside of their scope.
how do we create scope review
- What is the only way of creating local scope in JavaScript?
- Using the var keyword within a function body.
- Nothing else creates local scope!
how do we create scope review
- For those of you coming from other languages, note that block scope does not exist in JS.
- For those of you who only know JS- know that people coming from other languages will be slightly confused by not having block scope.
- Don't worry about this; just keep doing what you already are.
Block Scope Doesn't Exist in JS
var message = 'yes';
for(var i = 0; i < 5; i++){
var message = 'NO!';
};
console.log('Is there block scope? ' + message);
//'Is there block scope? NO!'
JavaScript only has LEXICAL scoping
Lexical Scoping = Function Scope with Nesting
Questions
Exercise Time!
- Repo?
- TAs?
- Pairs?
- References?
https://github.com/telegraphPrep/week3
- Slides
- The Internet!
- StackOverflow
CLOSURES
Closures
An ambassador (Jenny, from Kenya)
Closures
A function always maintains access to the execution scope it was born in
Lexical scoping
var closureAlert = function(){
var x = 'Help! I\'m a variable '+
'stuck in a closure!';
var alerter = function(){
alert(x);
};
alerter();
};
closureAlert();
Closure example #1
var closureAlert = function(){
var x = 0;
var alerter = function(){
x++;
alert(x);
};
return alerter;
};
var alerter1 = closureAlert();
var alerter2 = closureAlert();
alerter1();
alerter2();
Closure Example #2
var add = function(num){
var num1 = num;
var addToNum1 = function(num2){
return num1 + num2;
};
return addToNum1;
};
var addEleven = add(11);
var result = addEleven(22);
console.log(result);
Closure Example: counter
function counter() {
var n = 0;
return {
count: function() { n++; return n; },
reset: function() { n = 0; }
};
}
var c = counter();
var d = counter();
c.count();
d.count();
c.reset();
c.count();
d.count();
Recipe: creation
1. Create your parent function.
2. Define some variables in the parent's local scope.
(they can be accessed by the child function)
3. Define a function inside the parent function.
(aka defining a "child" function or "nested" function)
4. Return that child from inside the parent.
function outerFunc() { var parentVar = "local to parent"; function innerFunc() { return parentVar + ' but accessed by child!'; }; return innerFunc; }
1. 2. 3. 4.
RECIPE: Execution
function outerFunc() {
var parentVar = "local to parent";
function innerFunc() {
return parentVar + ' but accessed by child!';
};
return innerFunc;
}
// STEP 1 - Run the parent function.
var example = outerFunc();
console.log(example);
// We see example now stores the child.
// STEP 2 - Run the child function.
var result = example();
console.log(result);
// What's the end result?
Gotcha!?
var sayAlice = function(){
var makeLog = function() {
console.log(alice);
};
var alice = 'Why hello there, Alice!';
return makeLog;
};
var log = sayAlice();
log();
Example #2,350,987
var makeStopwatch = function(){
var elapsed = 0;
var stopwatch = function(){
return elapsed;
};
var increase = function(){ elapsed++; };
setInterval(increase, 1000);
return stopwatch;
};
var x = makeStopwatch();
Module Pattern - Boilerplate
var Module = function(){
var privateProperty = 'I like big fonts,' +
' and I cannot lie';
function privateMethod(params){
// do something
};
return {
publicProperty: 'JS rulez!!',
publicMethod: function(params){
// do something
},
privilegedMethod: function(params){
privateMethod(args);
}
};
};
Module Pattern - Example
var makeNewCar = function(){
var brakeLightsOn = false, seatbeltLocked = false;
function useABS(pressure) {
// 1. Use Electronic Brakeforce Distribution.
// 2. If necessary, activate Stability Control.
// 3. Check if wheels are locking up.
// 4. If necessary, release and re-apply EBD.
}
return {
color: 'blue',
honkHorn: function() {
console.log('HONK!!!');
},
hitBrakes: function(pressure){
brakeLightsOn = true;
seatbeltLocked = true;
useABS(pressure);
}
};
};
Questions
Exercises
Different format & new partners!
Quick Tip: When talking with your partner and TAs, practice using technical terminology. Be specific! Be precise!
var hello;
hello = 'hiiii!';
function foo() { }
var foo = function() {};
foo;
foo();
var woohoo = [1, 2, 3];
woohoo[i]
woohoo[0]
var yay = {
kool: 'aid'
};
kool
'aid'
kool: 'aid'
variable declaration (undefined variable)
assignment (value assigned to variable)
function definition/declaration
function definition/expression
function, function reference
function call/invocation
element of woohoo, woohoo-sub-i
first element, woohoo-sub-0
key, property name
value, property value
key-value pair, property of yay
E.g., never say "thing";
specify which element of an array;
mention line numbers.
Higher-Order
Functions
and Callbacks
Functions Review
What is a function?
1. A block of code
2. We get to determine when this code is run (invoked)
3. Directions for doing something we have created but not executed yet (figuring out driving directions vs. actually driving there; writing down a recipe vs. actually cooking it).
This seems super basic, but thinking of functions this way will make higher order functions a lot easier.
A function is just a block of code, and we get to decide when it is run.
1. Take a function as an input (argument)
Higher-Order Functions
var count = 1;
setInterval(function(){
console.log('I am', count++, 'seconds old now');
}, 1000);
2. Return a function as the output
var add = function(num){
var num1 = num;
var addToNum1 = function(num2){
return num1 + num2;
};
return addToNum1;
};
If a function does at least one of the following two things, then it is a baller higher-order function.
Higher-Order Functions
In JavaScript...
"higher-order" functions can exist because
JS treats functions as "first-class objects".
In other words...
functions can be:
- created (defined)
- stored (into variables)
- passed (as arguments)
- returned (by functions)
...just like any other object in JS
(just like numbers, strings, booleans, arrays, etc).
Callbacks
var ifElse = function(condition, isTrue, isFalse){
if(condition){
isTrue();
} else {
isFalse();
}
};
var logTrue = function(){ console.log(true); };
var logFalse = function(){ console.log(false); };
ifElse(true, logTrue, logFalse);
Callbacks
Remember from Week 1 that we had two main ways of creating a function?
//Anonymous function saved into a variable
var nameImprover = function (name, adj) {
return 'Col ' + name + ' Mc' + adj + ' pants';
};
//named function
function nameImprover(name, adj) {
return 'Col ' + name + ' Mc' + adj + ' pants';
}
//both work!
Callbacks
What if we didn't store the anonymous function into a variable? What if we just left it as is, a set of instructions we've created but not executed yet?
//Anonymous function
function (name, adj) {
return 'Col ' + name + ' Mc' + adj + ' pants';
};
Callbacks
var ifElse = function(condition, isTrue, isFalse){
if(condition){
isTrue();
} else {
isFalse();
}
};
ifElse(true,
function(){ console.log(true); },
function(){ console.log(false); }
);
var ifElse = function(condition, isTrue, isFalse){
if(condition){
isTrue();
} else {
isFalse();
}
};
var logTrue = function(){ console.log(true); };
var logFalse = function(){ console.log(false); };
ifElse(true, logTrue, logFalse);
Let's refactor our code to just use anonymous functions, instead of declaring them in a separate part of our code and saving them into variables.
Callbacks
var ifElse = function(condition, isTrue, isFalse){
if(condition){
isTrue();
} else {
isFalse();
}
};
ifElse(true,
function(){ console.log(true); },
function(){ console.log(false); }
);
This is a super common pattern in functional programming: to declare anonymous functions in-line as arguments.
Remember, a function is just a block of code we've defined but not run yet. If we're not using this code elsewhere in our program, there's no need to give it a name.
Passing Arguments
var ifElse = function(condition, isTrue, isFalse){
if(condition){
isTrue(); // no arguments
} else {
isFalse(); // no arguments
}
};
var ifElse = function(condition, isTrue, isFalse, arg){
if(condition){
isTrue(arg); // Look! An argument! Whoa.
} else {
isFalse(arg); // <(^.^<) OMG it's another one.
}
};
Passing Arguments
Or, if our higher order function will be giving us the arguments, we can just include those as parameters for our anonymous functions.
When would this happen? You can think of a higher-order function that might iterate through an array, and pass each item in the array to the callback function we pass in. In this case, we're not directly specifying the argument, we're letting the higher-order function give it to us each time.
Passing Arguments
var increment = function(n){
return n + 1;
};
var square = function(n){
return n*n;
};
var doMathSoIDontHaveTo = function(n, func){
return func(n);
};
doMathSoIDontHaveTo(5, square);
doMathSoIDontHaveTo(4, increment);
Where else are we going to use callbacks?
1. API requests (Get data from Yelp, and once you have that data some number of milliseconds later, invoke this function which is the code I've programmed to play with the Yelp data).
2. Event handlers- Whenever a user clicks on this square, do these things.
3. Functional programming! Tomorrow, I promise :)
Questions
Exercises
github.com/telegraphPrep/week3
New partners!
(again)
Underscore.js
underscore.js
What is it?
A popular library with many useful functional programming methods built in.
Where is it?
http://underscorejs.org
Annotated Source:
http://underscorejs.org/docs/underscore.html
Let's make some of the methods from scratch!
//_ is just an empty object that we put methods on
var _ = {};
//_.each is just a property of that object
//that property is set equal to a function
//that function has two parameters
_.each = function(list, callback) {
//function body here
};
//when you load up the underscorejs library
//all you're doing is loading an enormous object
//that has 200+ properties that are functions
Using the underscorejs library
What is this _ object that I'm invoking methods on?
_.each() usage
var pocketmons = ['Charisaur', 'Bulbazard', 'Twomew'];
var logger = function(val){
console.log(val);
};
_.each(pocketmons, logger);
//'Charisaur'
//'Bulbazard'
//'Twomew'
//_.each(list, iterator)
_.each() usage
- Iterates over a list of elements, giving them one at a time to an iterator function.
- Each invocation of iterator is called with three arguments: element, index, list. If list is an Object, iterator's arguments will be value, key, list.
We're going to write this out ourselves!
var each = function(list, iterator) {
//function body here to make each work
};
//Example invocation:
_.each(pocketmons, logger);
//'Charisaur'
//'Bulbazard'
//'Twomew'
http://underscorejs.org/#each
- Iterates over a list of elements, giving them one at a time to an iterator function.
- Each invocation of iterator is called with three arguments: value, index, list. If list is a JavaScript object, iterator's arguments will be value, key, list.
//PSEUDOCODE!!
//declare a function that has two parameters
//determine if collection is an array or an object
//loop through the collection
//invoke the callback on each element in the collection
_.EACH() DEFINED
http://underscorejs.org/#each
- Iterates over a list of elements, giving them one at a time to an iterator function.
var _ = {};
//declare a function that has two parameters
_.each = function(list, callback) {
//determine if collection is an array or an object
//loop through the collection
//invoke the callback on each element in the collection
};
_.EACH() DEFINED
http://underscorejs.org/#each
- Iterates over a list of elements, giving them one at a time to an iterator function.
var _ = {};
_.each = function(list, callback) {
//determine if list is an array or an object
if(Array.isArray(list)) {
//use array for loop
//invoke the callback on each element in the list
} else {
//use object for loop
//invoke the callback on each element in the list
}
};
_.EACH() DEFINED
http://underscorejs.org/#each
- Iterates over a list of elements, giving them one at a time to an iterator function.
var _ = {};
_.each = function(list, callback) {
if(Array.isArray(list)) {
for (var i = 0; i < list.length; i++) {
//invoke the callback on each element in the list
}
} else {
for (var key in list) {
//invoke the callback on each element in the list
}
}
};
_.EACH() DEFINED
http://underscorejs.org/#each
- Iterates over a list of elements, giving them one at a time to an iterator function.
var _ = {};
_.each = function(list, callback) {
if(Array.isArray(list)) {
for (var i = 0; i < list.length; i++) {
callback(list[i], i, list);
}
} else {
for (var key in list) {
callback(list[key], key, list);
}
}
};
_.EACH() DEFINED
Looping with _.each
function AnimalMaker(name) {
return {
speak: function () {
console.log("my name is ", name);
}
};
};
var animalNames = ['Frog', 'Falcon', 'Fox'];
var farm = [];
for(var i = 0; i < animalNames.length; i++){
farm.push(AnimalMaker(animalNames[i]));
}
function AnimalMaker(name) {
return {
speak: function () {
console.log("my name is ", name);
}
};
};
var animalNames = ['Frog', 'Falcon', 'Fox'];
var farm = [];
_.each(animalNames, function (name) {
farm.push(AnimalMaker(name));
});
- Let's refactor from our for loop to use _.each instead!
Simplicity vs Flexibility
var arr = ['a', 'b', 'c'];
for(var i = arr.length - 1; i >= 0; i--) {
// do stuff with elements in reverse order
}
for(var i = 0; i < arr.length; i += 2) {
// do stuff with even-indexed elements
}
each
- simple syntax
- straightforward and most commonly needed behavior
for
- ugly syntax
- flexible setup for customized behavior
Iterating over arrays:
Each vs For
Iterating over arrays:
Each vs For
For Loops
- Remember that typical for loops run the loop body once per element of the array.
- Every iteration gives the loop body a different number value of i
Each Loops
- The callback runs once per element of the array.
- Every iteration gives the callback a different element of the array.
_.EACH with Arrays:
Direct access to element
The callback gets the index and array as well, but don't use them to access the current element.
var names = ['Jeff', 'Preston', 'Bianca'];
function logTwice(name, index, names) {
var currentName = names[index]; // correct
console.log(currentName);
currentName = name; // correct AND easier
console.log(currentName);
}
_.each(names, logTwice);
Iterating Over Objects:
Each vs For-In
For-In Loops
- Remember that typical for-in loops run the loop body once per property of the object.
- Every iteration gives the loop body a different string value of the key (aka property name).
Each Loops
- The callback runs once per property of the object.
- Every iteration gives the callback a different property value of the object.
_.EACH with Objects:
Direct access to Property value
The callback gets the key and object as well, but don't use them to access the current property value.
var superheroes = {
batman : 'human',
superman : 'alien',
ironman : 'human',
groot : 'alien',
wolverine : 'mutant'
};
function logNameIfHuman(type, heroName, superheroes) {
var currentType = superheroes[heroName]; // correct
currentType = type; // correct AND easier
if(currentType === 'human') {
console.log(heroName);
}
}
_.each(superheroes, logNameIfHuman);
Nested Looping with _.each()
var studentA = {
firstName: 'Ryan',
lastName: 'Gosling'
};
var classA = {
subject: 'JavaScript',
teacher: '@RebootJeff',
students: [ /* studentA, studentB, etc... */ ]
};
var classes = [ /* classA, classB, etc... */ ];
for(var i = 0; i < classes.length; i++) {
for(var j = 0; j < classes[i].students.length; j++) {
var fullName = classes[i].students[j].firstName +
' ' + classes[i].students[j].lastname;
console.log(fullName);
}
}
_.each(classes, function(class) {
_.each(class.students, function(student) {
var fullName = student.firstName + ' ' + student.lastName;
console.log(fullName);
});
});
How do we print all the names
of all the students
of all the classes?
for(var i = 0; i < classes.length; i++) {
var students = classes[i].students; // This improves readability
for(var j = 0; j < students.length; j++) {
var fullName = students[j].firstName + ' ' + students[j].lastname;
console.log(fullName);
}
}
MUCH easier to read:
var pocketmon = ['Charisaur', 'Bulbazard', 'Twomew'];
var stokedFunc = function(val){
return val + '!!!';
};
var stokedPocketmon = _.map(pocketmon, stokedFunc);
_.MAP() usage
//_.map(list, iterator)
console.log(stokedPocketmon);
//['Charisaur!!!','Bulbazard!!!','Twomew!!!']
_.map() defined
var _ = { each: function(/*...*/) { /*...*/ } };
_.map = function(list, iterator) {
var result = []; // make a new array
_.each(list, function(item, index, list) {
result.push(iterator(item, index, list));
});
return result;
};
- Produces a new array of values by mapping each value in list through a transformation function (iterator).
- Each invocation of iterator is called with three arguments: (element, index, list). If list is a JavaScript object, iterator's arguments will be (value, key, list).
Looping with _.map
function AnimalMaker(name) {
return {
speak: function () {
console.log("my name is ", name);
}
};
};
var animalNames = ['Frog', 'Falcon', 'Fox'];
var farm = [];
_.each(animalNames, function (name) {
farm.push(AnimalMaker(name));
});
function AnimalMaker(name) {
return {
speak: function () {
console.log("my name is ", name);
}
};
};
var animalNames = ['Frog', 'Falcon', 'Fox'];
var farm = _.map(animalNames, function (name) {
return AnimalMaker(name);
});
function AnimalMaker(name) {
return {
speak: function () {
console.log("my name is ", name);
}
};
};
var animalNames = ['Frog', 'Falcon', 'Fox'];
// Remember coding WITHOUT Underscore?
var farm = [];
for(var i = 0; i < animalNames.length; i++){
farm.push(AnimalMaker(animalNames[i]));
}
_.map vs _.each
function AnimalMaker(name) {
return {
speak: function () {
console.log("my name is ", name);
}
};
};
var animalNames = ['Frog', 'Falcon', 'Fox'];
// Mapping builds up an array and returns it.
var farm = _.map(animalNames, function (name) {
return AnimalMaker(name);
});
// An each loop returns nothing.
// Just use it to iterate over an array.
_.each(farm, function (animal) {
animal.speak();
});
I want to simply loop through an array or object.
I want a new array based on an existing one.
Questions
Exercises
New partners!
(of course)
https://github.com/TelegraphPrep/week3
DEBRIEF
But wait! There's more!
- Underscore.js vs Lodash.js vs vanilla JS
- Go check out other Underscore methods/tools!
- Want to be a TA?
- Feedback:
- Difficulty level? Topics?
- Class format? Exercises?
- Organize some study groups amongst yourselves
- ...and don't forget THE MOST IMPORTANT THING!!!
Follow @RebootJeff
Read words on RebootJeff.com
(for coding + career advice)
If there is enough time
then we can discuss other topics such as...
- Other JavaScript topics
- Mutability
- Anonymous Functions vs Named Functions
- Other Software Engineering topics
- Privacy and Interfaces
- What does "API" really mean?
- Career stuff
- Daily life of a software engineer
- Roadmap / career path
- Hack Reactor
BUT... there are no slides or prepared materials for these topics.
(Treat this like a Q&A session)
Telegraph Prep Week 3: Scopes, Closures, Higher-Order Functions
By hrjr
Telegraph Prep Week 3: Scopes, Closures, Higher-Order Functions
An introduction to functional programming
- 2,838