Functional Programming
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!