JavaScript Fundamentals:

Functional

Slides:
https://slides.com/telegraphprep/

telegraphPrepWeek3

Variables as References

Scope

Closures

Callbacks

Higher-Order Functions

Creative Commons License

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

Review:

Basics of Functions

context

DRY!! (don't repeat yourself)

  • encapsulate repeated code into a function
  • less typing, fewer places for bugs

Readability

  • use expressive names for functions
  • code is more organized

Control flow

  • function can be invoked wherever you want and however many times you want

Why are Functions important?

Overview

  • Anatomy
  • Definition vs Invocation
  • Named Functions vs Anonymous
  • Parameters vs Arguments
  • Return Values and Side Effects

What is a function?

A set of instructions that we create. 

 

A block of code that we write that gets executed at some other point.

 

We use them to control the flow of our program.

 

Anatomy

var add = function (a, b) {

  return a + b;

};

add(1, 2);

declaration / definition

invocation / call time

< Note 'function'        keyword

< Note  invocation 

operator ()

Anatomy

var add = function (a, b) {

  return a + b;

};

add(1, 2);

body

Anatomy

var add = function (a, b) {

  return a + b;

};

add(1, 2);

arguments

parameters

anonymous function

function(item) {
  return item * 3;
}

An anonymous function has no name after the 'function' keyword

 

Often used as arguments to higher order functions

(we'll use these often in this class)

Named vs Anonymous

//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!

Invocation/Call-time

Declaring a function is like creating a recipe: you decide what the steps are, but nothing actually gets made.


Invoking a function is like baking that recipe: now that you know what the steps are, you get to actually do them!

 

The cool part about this is that you can pass in different ingredients to that recipe each time! And each one is run totally independently of all other times that recipe has been created. 

Invocation/Call-time

//Definition/Declaration:
var breadMaker = function(ingredient) {
  return 'fresh baked ' + ingredient + 'bread';
}

//Invocation:
breadMaker('banana nut');
breadMaker('guacamole');
//Putting () next to a function name means
  //that you are invoking it right then.

Arguments/Parameters

//When we define a function, what that function
//  takes in (it's signature) are called parameters
var nameImprover = function (name, adj) {
  return 'Col ' + name + ' Mc' + adj + ' pants';
};

//When we invoke a function, what we pass in to 
//that particular invocation are called arguments
nameImprover('preston','purple');

Arguments/Parameters

var add = function(a, b) {
  return a + b;
}

add(1, 2, 3);

Note:  the number of parameters and arguments don't have to match

var add = function(a, b, c) {
  return a + b;
}

add(1, 2);

c = undefined

if you're curious about how to access arguments with no corresponding parameter look up the "arguments object"

parameters with no corresponding argument are undefined

Return/Side Effects

//Returned value:
var nameImprover = function (name, adj) {
  return 'Col ' + name + ' Mc' + adj + ' pants';
};

//Side Effects:
var instructorName = 'preston';

var sideEffectImprover = function(adj) {
  instructorName = 'Col ' + instructorName + 
    ' Mc' + adj + ' pants';
};

Return/Side Effects

//Returned value:
var nameImprover = function (name, adj) {
  return 'Col ' + name + ' Mc' + adj + ' pants';
};
var returnResults = nameImprover('preston','purple');
returnResults; //'Col preston Mcpurple pants'

//Side Effects:
var instructorName = 'preston';
var sideEffectImprover = function(adj) {
  instructorName = 'Col ' + instructorName + 
    ' Mc' + adj + ' pants';
};

var sideEffectResults = sideEffectImprover('purple');
sideEffectResults; //undefined
instructorName; //'Col preston Mcpurple pants'

Why Use Side effects?

var logResults = console.log('side effects are useful');
logResults; //undefined

var addUserToDatabase = function(username, userObj) {
  if(database[username] === undefined) {
    database[username] = userObj;
  }
};
//note that we are not returning anything here. 
//we don't want to return the entire database
//and we already have the userObj since we had it
//to pass into addUserToDatabase.

//The function is clearly still useful, even though
//it doesn't return anything. 

Return ends function

var totallyHarmless = function() {
  return 'world peace';
  launchAllNuclearMissiles();
};
totallyHarmless(); //returns 'world peace'
//does not invoke launchAllNuclearMissiles
  //because that comes after the return statement
  //and return statements immediately stop the
  //function and end it.

tunnel- return

Since a function creates it's own local scope, the global* scope can't see anything that's going on inside that function body. 

The return value is the one way for the outside world to 'tunnel into' the function and see something that's going on. 

We can use side effects to save the work that a function that has done for us into a variable that's accessible in the global scope. 

Or, we can return a value, directly communicating the results to whatever we have in the global scope that's listening for the results of the function. 

tunnel- return

var testArr = [1,2,3,4];
var globalSum = 0;

var sumFunc = function(arr) {
  for (var i = 0; i < arr.length; i++) {
    globalSum += arr[i];
  }
  return 'string from sumFunc';
};

var returnVal = sumFunc(testArr);
console.log(globalSum); //10
console.log(returnVal); //'string from sumFunc'

key takeaways

Why are functions useful?

  • code reuse - DRY!! 
  • allow us to control when code gets executed
  • more organized and readable

Definition vs Invocation

  • defining the function is just like writing out the steps
  • the code doesn't get run until the function gets invoked/called

Parameters vs Arguments (function input)

  • parameters are variable names specified in the definition
  • arguments are values specified at invocation

key takeaways

Returned Values (function output)

  • whatever appears after the "return" keyword gets evaluated then provided as output when the function gets invoked
  • return exits out of the function, code that comes after doesn't get run
  • default return value is undefined

Side Effects

  • when something outside of the function scope gets affected. Examples:
    • a variable in an outer scope gets changed
    • browser actions - console.log, alert, prompt

Practice TIME!!

https://github.com/telegraphPrep/week3

under functions.js

Variables- values & references

context

Why do we care about the difference between a value and a reference?

To use objects, arrays, and functions effectively it's important to understand how they are referenced.

A lack of understanding will lead to bugs in your program and difficulty understanding more advanced JS concepts.

Let's talk about links and webpages

Let's create a link to my favorite webpage:

the San Francisco Bike Coalition

In fact, I like them so much, let's create several links to that same page.

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:

the San Francisco Bike Coalition

In fact, I like them so much, let's create several links to that same page.

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:

the San Francisco Bike Coalition

In fact, I like them so much, let's create several links to that same page.

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:

the San Francisco Bike Coalition

In fact, I like them so much, let's create several links to that same page.

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:

the San Francisco Bike Coalition

In fact, I like them so much, let's create several links to that same page.

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:

the San Francisco Bike Coalition

In fact, I like them so much, let's create several links to that same page.

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:

the San Francisco Bike Coalition

In fact, I like them so much, let's create several links to that same page.

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:

the San Francisco Bike Coalition

In fact, I like them so much, let's create several links to that same page.

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:

the San Francisco Bike Coalition

In fact, I like them so much, let's create several links to that same page.

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:

the San Francisco Bike Coalition

In fact, I like them so much, let's create several links to that same page.

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.

Key Takeaways

Store values

Primitives

var num = 1

var foo = "bar"

var bool = true

var nothing = null

var notDef = undefined

Store References

Objects

var obj = { foo: 'bar' }

var arr = [0, 1, 2, 3]

var func = function(x) { ... }

Exercise time!!

Pair Programming

http://slides.com/telegraphprep/

pair-programming#/

 

Repo

https://github.com/telegraphPrep/week3

Scope

It's all about variable access...

Scope determines what variables are available for you to use at any given point in your program.

What is scope and why does it matter?

You can 'hide' variables in functions (local scopes)

-OR-

make variables available everywhere (global scope). 

  1. To have multiple for loops all using i as their iterator
  2. 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. 
  3. 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;
};
func();

console.log(local);
  ReferenceError: local is not defined
  • What does local scope mean? 
  • It simply means that variables declared in a function are 'hidden' from the rest of the program
  • That is, they only exist in this scope. 

Note: keyword var is important here!

Local Scope

var global;
var func = function(){
  var local = true;
};
func();
console.log(local);


console.log(global); //undefined
  • A variable will be undefined if it exists (was declared) 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

  • 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!';
}
//inside a function
function addToGlobalScope(){
  y = 'global here, too!';
}

Global Scope

What gets print to the console?

Let's walk through the code as the JS interpreter...

console.log(y) //???
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!

addToGlobalScope();
console.log(y); //???
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

The var keyword is important!

It creates a variable and then assigns it to the current 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.

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();
  

Let's walk through how this code gets executed...

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. 

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. 
var nameMaker = function(name) {
    return {name: name};

};

var albreyObject = nameMaker('Albrey'); // {name: 'Albrey'}
var shannaObject = nameMaker('Shanna'); // {name: 'Shanna'}

// each time we invoke nameMaker, a new scope is created

passing variables into scopes

Arguments are values that are passed into the local scope of the corresponding function

var nameMaker = function(name) {
    return {name: name};

};

var albreyObject = nameMaker('Albrey'); // {name: 'Albrey'}
var shannaObject = nameMaker('Shanna'); // {name: 'Shanna'}

// 'Albrey' and 'Shanna' become local variables to nameMaker 
// when passed into the function

returning variables from functions

The only way to access a local variable from the global scope is by returning it from the function

var nameMaker = function(name) {
    var obj = {name: name};
};

var nameMaker2 = function(name) {
    var obj = {name: name};
    return obj;
};
var albreyObject = nameMaker('Albrey'); // undefined
// We can't access obj in nameMaker because we didn't return it

var shannaObject = nameMaker2('Shanna'); // {name: 'Shanna'}
// We can access obj in nameMaker2 because we returned it

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. 

Key takeaways

  • Scope determines variable accessibility
  • "Execution scopes" are created every time you invoke a function

Key takeaways

Lexical Scoping, nested functions, and precedence

  • In JS there is only function scope, no block scope
  • Nested functions have access to variables declared in their outer scope
  • Variable lookup starts in local scope then goes outward

Key takeaways

Local vs Global

  • Local scope variables - declared within a function body and only accessible within that function
  • Global scope variables - any that are not declared within a function body 
    • if you don't use the "var" keyword in a function, the variable gets put on the global scope

Questions

Exercise Time!

  • Repo?
  • TAs?
  • Pairs?
  • References?

https://github.com/telegraphPrep/week3

  • Slides
  • The Internet!
  • Google
  • StackOverflow

Exercise time!!

Pair Programming

http://slides.com/telegraphprep/

pair-programming#/

 

Repo

https://github.com/telegraphPrep/week3

scopes, pt 2

 
 
var firstAlert = function(){
  var x = 'Secret Message';
  
  var alerter = function(){
    alert(x);
  };
  
  alerter();
};
firstAlert();

Nested Inner Function

Inner function called within outer function

Let's walk through this code together as though we were the JS interpreter...

 
var firstAlert = function(){
  var x = 'Secret Message';
  
  var alerter = function(){
    alert(x);
  };
  
  setTimeout(alerter, 1000);
  console.log('will still run right after');
};

firstAlert();

Nested Inner Function

Inner func called within browser-land

Let's pop this code into the console and see what happens...

 
var firstAlert = function(){
  var x = 'Secret Message';
  
  var alerter = function(){
    alert(x);
  };
  
  return alerter;
};

var alert1 = firstAlert();
alert1();

Returned Inner Function

Inner function called where?

var firstAlert = function(){
  var x = 'Secret Message';
  
  var alerter = function(){
    alert(x);
  };
  
  return alerter;
};

var alert1 = firstAlert();

called outside of outer function

var add = function(num){
  var num1 = num;

  var addToNum1 = function(num2){
    return num1 + num2;
  };

  return addToNum1;
};

var alwaysAdd2 = add(2);

Returned Inner Function

var add = function(num){
  var num1 = num;

  var addToNum1 = function(num2){
    return num1 + num2;
  };

  return addToNum1;
};

var alwaysAdd2 = add(2);
alwaysAdd2(3); //??
var add = function(num){
  var num1 = num;

  var addToNum1 = function(num2){
    return num1 + num2;
  };

  return addToNum1;
};

var alwaysAdd2 = add(2);
alwaysAdd2(3); //5
var alwaysAdd10 = add(10);
var add = function(num){
  var num1 = num;

  var addToNum1 = function(num2){
    return num1 + num2;
  };

  return addToNum1;
};

var alwaysAdd2 = add(2);
alwaysAdd2(3); //5
var alwaysAdd10 = add(10);
alwaysAdd10(3); //??
var add = function(num){
  var num1 = num;

  var addToNum1 = function(num2){
    return num1 + num2;
  };

  return addToNum1;
};

var alwaysAdd2 = add(2);
alwaysAdd2(3); //5
var alwaysAdd10 = add(10);
alwaysAdd10(3); //13

questions?

 

Congratulations! You now know closures!

 

Why are closures important?

  • access private variables (ex: module pattern)
  • partial application of arguments (currying)*
  • recursion involving memoization*

 

*advanced topics not covered in this class

Closure Definition

Closure functions are declared inside outer functions (nested) and invoked in a context outside of the one they were created in.

They retain access to a closure variable from the context the function was created in.

Remember a closure consists of

TWO key components:

  • closure function
  • closure variable

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.

closure variable

closure function

RECIPE: Execution

function outerFunc() {
  var parentVar = "local to parent";
  function innerFunc() {
    return parentVar + ' but accessed by child!';
  };
  return innerFunc;
}

// STEP 1 - Invoke the parent function.
var example = outerFunc();
console.log(example);
// We see example now stores the child function.

// STEP 2 - Invoke the child function.
var result = example();
console.log(result);
// What's the end result?

Closure Definition,  revisited

Closure functions are declared inside outer functions (nested) and invoked in a context outside of the one they were created in.

A: outside of scope it was created in

Q: where is closureFunc getting invoked?

var firstAlert = function(){
  var x = 'Secret Message';
  var alerter = function(){
    alert(x);
  };
  alerter();
};
firstAlert();
var firstAlert = function(){
  var x = 'Secret Message';
  var alerter = function(){
    alert(x);
  };
  return alerter;
};
firstAlert();
var firstAlert = function(){
  var x = 'Secret Message';
  var alerter = function(){
    alert(x);
  };
  return alerter;
};
firstAlert()();

Closure Definition,  revisited

Closure functions retain access to closure variables from the context the function was created in.

var firstAlert = function(){
  var x = 'Secret Message';
  var alerter = function(){
    alert(x);
  };
  return alerter;
};
var myAlert = firstAlert();
// myAlert still has access to x

Exercises

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.

Gotcha!?

var sayAlice = function(){

  var makeLog = function() {
    console.log(alice);
  };

  var alice = 'Why hello there, Alice!';

  return makeLog;
};

var log = sayAlice();

log(); //??

What will we see in the console?

Walk through the code as the JS interpreter would

Scope is created at runtime

var makeStopwatch = function(){
  
  var elapsed = 0;
  var increase = function(){ elapsed++; };
  setInterval(increase, 1000);

  var stopwatch = {
    getTime: function() { return elapsed; }
  };

  return stopwatch;

};

var watch1 = makeStopwatch();
// wait 3 seconds...
var watch2 = makeStopwatch();
watch1.getTime() - watch2.getTime(); //??

how many "elapsed" variables are created?

everytime makeStopwatch is invoked, a new closure comes into existence

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){ 
      var args = params;
      privateMethod(args); 
    }
  };
};

Module Pattern - Example

var makeNewCar = function(){  
  var brakeLightsOn = false, seatbeltLocked = false; // private properties

  function useABS(pressure) {  // private method
    // 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', // public property
    honkHorn: function() { // public method
      console.log('HONK!!!');
    },
    hitBrakes: function(pressure){ //privileged method
      brakeLightsOn = true; // private property
      seatbeltLocked = true; // private property
      useABS(pressure); // private method
    }
  };

};

key takeaways

Closures functions are nested inside outer functions and retain access to closure variables in the context the function was created in

 
function outerFunc() {
  var closureVar = "Only the closureFunc can access me!";
  function closureFunc() {
    console.log('closureVar says:', closureVar);
  }
  return closureFunc;
};

var innerFunc = outerFunc();
innerFunc(); // this is the closure function
// --> "closureVar says: Only the closureFunc can access me!" 

key takeaways

Each invocation of the outer function creates a NEW closure function and a corresponding NEW closure variable. 

function counter() {
  var n = 0;

  return {
    count: function() { n++; return n; },
    reset: function() { n = 0; }
  };
}

var counter1 = counter();
var counter2 = counter();
var counter3 = counter();

How many variables "n" are created?

key takeaways

The module pattern can be used to create a public interface for private variables and functions.

Questions

Exercise Time!

  • Repo?
  • TAs?
  • Pairs?
  • References?

https://github.com/telegraphPrep/week3

  • Slides
  • The Internet!
  • Google
  • StackOverflow

Higher-Order
Functions

and Callbacks

Context

Why do we care about higher order functions and callbacks?

So that we can write more declarative and expressive code

// declarative style
var add10 = function(num) {
  console.log(num + 10);
};

var nums = [1,2,3]
nums.forEach(add10);

// 11, 12, 13
// imperative style
var nums = [1,2,3];

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

// 11, 12, 13

Which is more clear to you?

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

// higher order function
var ifElse = function(condition, isTrue, isFalse){
  if(condition){
    // callback function
    isTrue();
  } else {
    // callback function
    isFalse();
  }
};
var logTrue = function(){ console.log(true); };
var logFalse = function(){ console.log(false); };

ifElse(true, logTrue, logFalse);

Callbacks are functions that you pass and invoke inside of higher order functions.

Callbacks: Anonymous functions

Remember from Week 1 that we had two main ways of creating a function? 

//Anonymous function saved into a variable
var nameCreator = function (firstName, lastName) {
  return firstName + ' ' + lastName
};

//named function
function nameImprover(firstName, lastName) {
  return firstName + ' ' + lastName
}

//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 (firstName, lastName) {
  return firstName + ' ' + lastName
};

Callbacks

var ifElse = function(condition, isTrue, isFalse){
  if(condition){
    isTrue();
  } else {
    isFalse();
  }
};

ifElse(true,
 function(){ console.log(true); },
 function(){ console.log(false); }
);

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. 

var ifElse = function(condition, isTrue, isFalse){
  if(condition){
    isTrue();
  } else {
    isFalse();
  }
};

ifElse(true,
 function(){ console.log(true); }, // this was logTrue()
 function(){ console.log(false); }// this was logFalse()
);

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.
  }
};
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 doMath = function(n, func){
  return func(n);
};

doMath(5, square);

doMath(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! Next week, I promise :)

Key takeaways

  • A higher order function is a function that takes a function as input and/or returns a function as output

  • "Callback" is a term used for any function that is passed as an argument to a function
    • they can be named or anonymous
    • arguments for callbacks can be passed as arguments to the higher order function

Questions

Exercises

github.com/telegraphPrep/week-3-introToHigherOrderFunctions

New partners!

(again)

Underscore.js

Context

What we'll do today...

Concepts we'll cover:

  • collections (objects and arrays)
  • higher order functions and callbacks
  • pseudocode

Bring together all of the concepts we've learned to build handy methods that will make our code cleaner and more expressive

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:

Exercises

 

https://github.com/TelegraphPrep/week3

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.

Key takeaways

  • Functional programming is more expressive and readable (think each and map vs using for loops)
  • The iterator callback function gets called and passed element in the collection argument
  • _.each basically does what a for loop does 
    • you can't return anything from its callback
  • _.map produces a new array 
    • it's callback requires a return statement

Questions

Exercises

 

https://github.com/TelegraphPrep/week3

Week 3: Scopes, Closures, Higher-Order Functions

By telegraphprep

Week 3: Scopes, Closures, Higher-Order Functions

An introduction to functional programming

  • 2,628