Functional JavaScript

Joel Ross

Functions

function sayHello(personName){
    return "Hello, " + personName;
}

const msg = sayHello("Joel");
console.log(msg); //"Hello Joel"

FUNCTIONS

 

ARE ALSO

VALUES

Functions are Values

Functions are a type of value (just like number, string, array).
Anywhere you can put an Array, you can put a Function.

They can be assigned as values to other variables.

//assign array to variable
const myArray = ['a','b','c'];



typeof myArray //=> 'object'
const other = myArray;

//access value in other
console.log( other[1] ); //print 'b'
//assign function to variable
function sayHello(name) { 
   console.log("Hello, "+name);
}

typeof sayHello // 'function'
const other = sayHello;

//prints "Hello, everyone"
other('everyone'); 

special array ability

special function ability

Function Literals

const array = [1,2,3]; //named variable (not anonymous)
console.log(array); //pass in named var

console.log( [4,5,6] ); //pass in literal/anonymous value

Functions can be written as literal values, also called an anonymous value (values not assigned a name/label).

//named function
function sayHello(person){ 
   console.log("Hello, "+person); 
}
//named function
function sayHello(person){ 
   console.log("Hello, "+person); 
}

//function literal (anonymous function) - technically invalid
function(person) {
   console.log("Hello, "+person);
}
//named function
function sayHello(person){ 
   console.log("Hello, "+person); 
}

//function literal (anonymous function) - technically invalid
function(person) {
   console.log("Hello, "+person);
}

//function literal (anonymous function, a value)
//assigned to variable
const sayHello = function(person) {
   console.log("Hello, "+person);
}

So they can be assigned to properties (values) in Objects.

const obj = {};
const myArray = ['a','b','c'];



//assign array to object
obj.array = myArray;

//access with dot notation
obj.array[0]; //gets 'a'


//assign literal (anonymous value)
obj.otherArray = [1,2,3]
const obj = {}
function sayHello(name) { 
   console.log("Hello, "+name);
}

//assign function to object
obj.sayHi = sayHello;

//access with dot notation
obj.sayHi('all'); //prints "Hello, all"


//assign literal (anonymous value)
obj.otherFunc = function() { 
    console.log("Hello world!");
}

this is how you make
"non-static" methods

Functions are Values

Functions are Values

So they can be passed as parameters to other functions!

const myArray = ['a','b','c'];



//takes array as an argument
//will access the arg array
//with an index of 1
function doWithOne(array) {
  console.log( array[1] );
}



//call function and pass value
doWithOne(myArray); //prints 'b'


//pass literal (anonymous value)
doWithOne([1,2,3]) //prints '2'

function sayHello(name) { 
   console.log("Hello, "+name);
}

//takes ANOTHER FUNCTION as an arg
//will call the arg function, 
//passing it "world"
function doWithWorld(aFunction) {
   aFunction("world");
}



//call function and pass value
doWithWorld(sayHello); //"Hello world"


//pass literal (anonymous value)
doWithWorld(function(msg) {
  console.log("you said: "+msg);
}); //prints "you said: world"
/* note where parens and braces close! */

array ability with hard-coded value

function ability with hard-coded value

Passing vs. Calling

When you pass a function as an argument, do not include parentheses after it. Including parentheses calls the function (executes it), and replaces that expression with the returned value.

function sayHello() { //version with no args
    return "Hello";
}

//print out the function
console.log( sayHello ); // logs "[Function: sayHello]" 
                         // the function

//resolve the expression, THEN print that out
console.log( sayHello() ); // logs "Hello", which is 
                           // what `sayHello()` resolves to.

Callback Functions

A term for a function that is passed into another function for the receiver to "call back to" and execute later.

//takes in TWO callback functions!
function doTogether(firstCallback, secondCallback){
    firstCallback();  //execute the first function
    secondCallback();  //execute the second function
    console.log('at the "same time"!');
}

function patHead() {
    console.log('pat your head');
}

function rubBelly() {
    console.log('rub your belly');
}

//pass in the callbacks to do them together
doTogether(patHead, rubBelly);

no parens, not calling now (just passing the variable!)

Using Callbacks

Many built-in functions (as well as library functions) expect callback functions as arguments.

//Arbitrary list of people's names, heights, and weights
const peopleArray = [{name: 'Ada', height: 64, weight: 135},{name: 'Bob', height: 74, weight: 156},{name: 'Chris', height: 69, weight: 139},{name: 'Diya', height: 69, weight: 144},{name: 'Emma', height: 71, weight: 152}]

//a function to "sort" people objects. Returns
//  < 0 if A comes before B, 
//  > 0 if B comes before A
//  0 if A and B stay in current order
function sortByHeightFunction(personA, personB) {
  if(personA.height < personB.height) {
    return -1; //person A is shorter, so they come first
  } else if(personB.height < personA.height) {
    return 1; //person B is shorter, so they come first 
  } else {
    return 0;
  }
}

peopleArray.sort(sortByHeightFunction); //sorts in place!

We will occasionally write functions that expect callbacks, but we will pass many callbacks to existing functions!

JS: Functional Looping

Joel Ross

Array Iteration

To iterate through each item in an array you can, use
the .forEach() function and pass it a callback to execute on each array item.

This function has a for loop in it already.

//Iterate through an array
const array = ['a','b','c'];
const printItem = function(item) {
   console.log(item);
}

array.forEach(printItem);

//more common to use anonymous function literal
array.forEach(function(item) {
   console.log(item);
});

callback

Mapping

function square(n) { //a function that squares a number
    return n*n;
}

const numbers = [1,2,3,4,5];  //an initial array

//transform the numbers using the square() function
const squares = []; //the transformed array
for(let i=0; i<numbers.length; i++) {
   const transformed = square(numbers[i]);
   squares.push(transformed); //add transformed to array
}
console.log(squares); // [1, 4, 9, 16, 25]

The .map() function applies the given callback function to each element in an array and returns a new array of the transformed values.

This function has a for loop in it already.

function square(n) { //a function that squares a number
    return n*n;
}

const numbers = [1,2,3,4,5];  //an initial array

//map the numbers using the `square` transforming function
const squares = numbers.map(square);




console.log(squares); // [1, 4, 9, 16, 25]




const numbers = [1,2,3,4,5];  //an initial array

//map the numbers using function literal (anonymous callback)
const squares = numbers.map(function(n) {
    return n*n;
})


console.log(squares); // [1, 4, 9, 16, 25]

this function does the for loop!

Practice

Define an array peopleNames that contains the names of 3 people (e.g., you and your neighbors).

 

Use the map() function to create a new array peopleGreetings containing strings "Hi _____!", where the _____ is the name of each person in the peopleNames array.

Filtering

The .filter() function applies the given callback function to each element in an array and returns a new array containing only those elements for which the callback returns true.

This function has a for loop in it already.

const numberArray = [3,1,4,2,5];

const isACrowd = array.filter(function(n) { 
   return n >= 3; //keep if > 3
}); //returns [3,4,5]

Reducing

The .reduce() function uses the given callback function to aggregate (combine) the elements in the list into a single value. Similar to the summarize() function in R.

function link(accumulation, newItem) { //combines two strings
    const newAccumulation = accumulation + "->" + newItem;
    return newAccumulation;
}

const letters = ['a','b','c','d','e'];  //an initial array

let linked = ""; //an accumulated aggregate, start at ""
for(let i=0; i<letters.length; i++){
    linked = link(linked, letters[i]);
}
console.log(linked); //"->a->b->c->d->e"

Reducing

The .reduce() function uses the given callback function to aggregate (combine) the elements in the list into a single value. Similar to the summarize() function in R.

function link(accumulation, newItem) { //combines two strings
    const newAccumulation = accumulation + "->" + newItem;
    return newAccumulation;
}

const letters = ['a','b','c','d','e'];  //an initial array

const linked = letters.reduce(link, ""); //pass func, starting value



console.log(linked); //"->a->b->c->d->e"

Practice

Define an array phoneDigits that is an array of the 7 digits in your phone number (e.g., [8, 6, 7, 5, 3, 0, 9].

 

Use the reduce() function to get the largest number in this array. Hint: use an if statement in the reducer callback to return the new "current maximum" value seen so far.

map, filter, and reduce
explained with emoji 😂

[🐮, 🥔, 🐔, 🌽].map(cook)
  => [🍔, 🍟, 🍗, 🍿]

[🍔, 🍟, 🍗, 🍿].filter(isVegetarian)
  => [🍟, 🍿]

[🍔, 🍟, 🍗, 🍿].reduce(eat)
  =>  💩

💩