Functional Programming

6 minute read

Published:

This lesson covers JavaScript Functional Programming.

Functions are Variables

  • JavaScript was based on Scheme, functional programming language

    • Functional Programming Language is centered on functions rather than variables, objects, or statements as in imperative statements
    • JavaScript supports number of functional programming features
  • Functions can be organized and manipulated like variables

    • function sayHello(name) {
          console.log("Hello, "+name);
      }
          
      console.log(typeof sayHello);  //=> 'function'
      
  • Functions as things (nouns), rather than as behaviors (verbs)

    • function sayHello(name) {
          console.log("Hello, "+name);
      }
          
      let greet = sayHello;
          
      greet("world");  //logs "Hello world"
      

Anonymous Functions

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

console.log( [4,5,6] ); //pass in anonymous value
function sayHello(person){
    console.log("Hello, "+person);
}

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

let sayHello = function(person) {
    console.log("Hello, "+person);
}
// like let myVar = [1,2,3]
//these produce the same function
function foo(bar) {}
let foo = function(bar) {}
  • Difference between these two constructions is one of ordering.
    • JavaScript interpreter will put variable and function declarations into memory before it executes a file - called hoisting
    • Hoisting only works for named function declarations
    • Always declare and define functions before using

Object Functions

  • can be assigned to properties of objects (as values)

  • //an object representing a dog
    let dog = {
        name: 'Sparky'
        breed: 'mutt'
    }
      
    //assign an anonymous function to the `bark` property
    dog.bark = function(){
        console.log('woof!');
    }
      
    //call the function
    dog.bark(); //logs "woof!"
    

Callback Functions

  • Can be passed as parameters to other functions since functions are values

  • A function that is passed into another is commonly referred to as a callback function: it is an argument that the other function will “call back to” and execute when needed.

    • //create a function `sayHello`
      function sayHello(name){
          console.log("Hello, "+name);
      }
          
      //a function that takes ANOTHER FUNCTION as an argument
      //this function will call the argument function, passing it "world"
      function doWithWorld(funcToCall){
          //call the given function with an argument of "world"
          funcToCall("world");
      }
          
      doWithWorld(sayHello);  //logs "Hello world";
      
      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);
      
    • anonymous callback functions:

    • //name anonymous function by assigning to variable
      let sayHello = function(name){
          console.log("Hello, "+name);
      }
          
      function doWithWorld(funcToCall){
          funcToCall("world");
      }
          
      //pass the named function by name
      doWithWorld(sayHello);
          
      //pass in anonymous version of the function
      doWithWorld(function(name){
          console.log("Hello, "+name);
      });
      

Closures

  • Functions can be returned as results to other functions

  • //This function produces ANOTHER FUNCTION
    //which greets a person with a given greeting
    function makeGreeterFunc(greeting){
        //explicitly store the param as a local variable (for clarity)
        let localGreeting = greeting;
      
        //A new function that uses the `greeting` param
        //this is just a value!
        let aGreeterFunc = function(name){
            console.log(localGreeting + " " + name);
        }
      
        return aGreeterFunc; //return the value (which happens to be a function)
    }
      
    //Use the "maker" to create two new functions
    let sayHello = makeGreeterFunc('Hello'); //says 'Hello' to a name
    let sayHowdy = makeGreeterFunc('Howdy'); //says 'Howdy' to a name
      
    //call the functions that were made
    sayHello('world'); //"Hello world"
    sayHello('Dave'); //"Hello Dave"
    sayHowdy('world'); //"Howdy wold"
    sayHowdy('partner'); //"Howdy partner"
    

Functional Looping

let person1 = {
    first: 'first1',
    last: 'last1'
}

let person2 = {
    first: 'first2',
    last: 'last2'
}

let person3 = {
    first: 'first3',
    last: 'last3'
}

let persons = [person1, person2, person3];

for(let i=0; i<persons.length; i++){
  let person = persons[i];
  console.log('Hello ' + person.first + ' ' + person.last);
}
let person1 = {
    first: 'first1',
    last: 'last1'
}

let person2 = {
    first: 'first2',
    last: 'last2'
}

let person3 = {
    first: 'first3',
    last: 'last3'
}

let persons = [person1, person2, person3];

function greeting(person){
    console.log('Hello ' + person.first + ' ' + person.last);
}

persons.forEach(greeting);
//an object representing a dog
let person1 = {
    first: 'first1',
    last: 'last1'
}

let person2 = {
    first: 'first2',
    last: 'last2'
}

let person3 = {
    first: 'first3',
    last: 'last3'
}

let persons = [person1, person2, person3];

persons.forEach(function(person){
    console.log('Hello ' + person.first + ' ' + person.last);
})

Map

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

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

let squares = []; //the transformed array

for(let i=0; i<numbers.length; i++){
    let transformed = square(numbers[i]); //call our square() function
    squares.push(transformed); //add transformed to the list
}

console.log(squares); // [1, 4, 9, 16, 25]
function square(n) { //a function that squares a number
    return n*n;
}

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

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

console.log(squares); // [1, 4, 9, 16, 25]
let numbers = [1,2,3,4,5];  //an initial array

let squares = numbers.map(function(item){
    return n*n;
});

Filter

function isEven(n) { //a function that determines if a number is even
    let remainder = n % 2; //get remainder when dividing by 2 (modulo operator)
    return remainder == 0; //true if no remainder, false otherwise
}

let numbers = [2,7,1,8,3];  //an initial array

let evens = []; //the filtered array
for(let i=0; i<numbers.length; i++){
    if(isEven(numbers[i])){
        evens.push(numbers[i]);
    }
}

console.log(evens); //[2, 8]
function isEven(n) { //a function that determines if a number is even
    return (n % 2) == 0; //true if no remainder, false otherwise
}

let numbers = [2,7,1,8,3];  //an initial array

let evens = numbers.filter(isEven); //the filtered array

console.log(evens); //[2, 8]
let numbers = [2,7,1,8,3];  //an initial array

let evens = numbers.filter(function(n) { return (n%2)==0; }); //one-liner!
let numbers = [1,2,3,4,5];  //an initial array

//get the squares of EVEN numbers only
let filtered = numbers.filter(isEven);
let squares = filtered.map(square);

console.log(squares); //[4, 16, 36]

//or in one statement, using results anonymously
let squares = numbers.filter(isEven).map(square);

console.log(squares); //[4, 16, 36]

Reduce

function add(x, y) { //a function that adds two numbers
    return x+y;
}

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

let runningTotal = 0; //an accumulated aggregate
for(let i=0; i<numbers.length; i++){
    runningTotal = add(runningTotal, numbers[i]);
}
console.log(runningTotal); //15
function add(x, y) { //a function that adds two numbers
    return x+y;
}

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

let sum = numbers.reduce(add);
console.log(sum); //15
function add(x, y) { //a function that adds two numbers
    return x+y;
}

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

//sum starting from 10
let sum = numbers.reduce(add, 10);

console.log(sum); //25
let numbers = [1,2,3,4,5];  //an initial array

//sum starting from 10
numbers.reduce(function(x, y){
    return x+y;
}, 10); //the starting value comes AFTER the callback!