Omer Goldberg
28 Feb 2018
•
6 min read
Note: This is part of the “Javascript and Functional Programming” series on learning functional programming techniques in JavaScript ES6+. To start from the ground up check out <Part 1>
Before we get started, there’s something you need to know … If you’ve ever programmed in JS you’ve probably used FP patterns before! These patterns and paradigms have been there all along, we just haven’t been able to see them properly. We are going to start from the familiar and explore new territory. Things may get a bit … well … strange. But fear not! Together we will survive!
Before we get started, there’s something you need to know … If you’ve ever programmed in JS you’ve probably used FP patterns before! These patterns and paradigms have been there all along, we just haven’t been able to see them properly. We are going to start from the familiar and explore new territory. Things may get a bit … well … strange. But fear not! Together we will survive!
In the following example we will declare a const and assign it an anonymous arrow functions.
After the initial assignment constFunction is a constant with a value of a function. We verify that by logging the constFunction variable in the Chrome inspector. Because constFunction is a function we can also invoke it.
Now that we understand that variables can hold functions, let’s demonstrate a function as a value of a key in an object. This should be familiar for anyone who has done any object oriented programming before.
const functionAsObjectProperty = {
print: (value) => console.log(value)
};
functionAsObjectProperty.print("mic check"); // "mic check"
When functions are first class objects we can pass them as data to an array, just like any other data type. Let’s use the Chrome console and check this out.
Now that we’ve warmed up, let’s get to the interesting stuff :) JS developers see functions that accept other functions as arguments on a daily basis. If you’re coming from a language that doesn’t support FP this should seem a bit weird 😳😳😳😳😳😳😳 Let’s acquaint ourselves with this concept by looking at some examples.
An asynchronous function that accepts a callback function.
const jsonfile = require('jsonfile')
const file = '/tmp/data.json'
const obj = {name: 'JP'}
const errorLoggerFunction = (err) => console.error(err);
jsonfile.writeFile(file, obj, errorLoggerFunction)
We’re using the jsonfile npm module in this example for the writeFile method. The third parameter that writeFile is expecting is a function. When the jsonfile.writeFile method executes it will either succeed or fail. If it fails it will execute the errorLoggerFunction. Alternatively, we could have gone for a more terse syntax, and dropped the named function:
const jsonfile = require('jsonfile')
const file = '/tmp/data.json'
const obj = {name: 'JP'}
jsonfile.writeFile(file, obj, (err) => console.error(err))
const timeout = () => {
setTimeout(() => alert("WoW"), 1000);
}
This example shows the built in asynchronous setTimeout method which accepts 2 arguments. Let’s formalize this a little bit and explain the setTimeout function in functional programming terms.
Let’s start by reading the signature of the function. We can observe that the number of arguments that setTimeout takes is two. In functional programming the number of arguments a function takes is called its Arity, from words like unary, binary, ternary etc. So we can say that setTimeout is of arity 2, or equivalently say that is a binary function.
The arguments that setTimeout expects is a function and a time interval to wait before executing the given function. Hmmm … another function that accepts a function as input?
In functional programming this is so common that these types of functions even have a name! They are called higher order functions.
There you go. Now you can drop this term low key in any random conversation at work / with friends and sound like a boss! 😂😂😂
Let’s get a little funkier and create an array (list) of functions in the next example.
const add = (x,y) => x + y;
const subtract = (x,y) => x - y;
const multiply = (x,y) => x * y;
const arrayOfFunctions = [add, subtract, multiply];
arrayOfFunctions.forEach(calculationFunction => console.log(calculationFunction(1,1))); // 2 0 1
On line 5 we are declaring an array of functions. We are then using the forEach method to iterate over the array. forEach is a natively supported ES6+ function, that accepts a function to execute on every item in the array. Therefore, forEach is also a higher order function!
Our forEach accepts an anonymous function as input. forEach will iterate over the array and implicitly access the current item in the array and call it getCalculation. It is worth noting that forEach implicitly accesses array elements, in comparison to how we would have accessed the current element if we had used a regular for loop — ie. arrayOfFunctions[i]. Every item in our array is a function, therefore we invoke getCalculation with the arguments that it is expecting.
Fantastic. This example illustrates that functions in functional programming can be passed into arrays (lists) just like any other data type. Functions can go anywhere!
Now let’s build our own higher order function!
const addWrapper = () => (x,y) => x + y;
const add = addWrapper();
const sum1 = add (1,2); // 3
// Or we could do it like this
const sum2 = addWrapper()(4,4); // 8
The addWrapper function returns a simple addition function when called. By invoking the result of the addWrapper function and supplying it two arguments, we have access to the anonymous addition function.
We could get even crazier with our level of indirection and write a function that returns a function, that in turn returns its own function!
const bankStatement =
name =>
location =>
balance =>
`Hello ${name}! Welcome to the bank of ${location}. Your current balance is ${balance}`;
const statementExpectingLocation = bankStatement("Omer");
const statementExpectingBalance = statementExpectingLocation("NYC");
const bankStatementMsg = statementExpectingBalance("100 million"); // wishful thinking?
console.log(bankStatementMsg); // Hello Omer! Welcome to the bank of NYC. Your current balance is 100 million
// We could also call the function with all the arguments up front
const msg = bankStatement("Jeff Bezos")("Silicon Valley")("97.7 billion");
console.log(msg); // Hello Jeff Bezos! Welcome to the bank of Silicon Valley. Your current balance is 97.7 billion
This is a very powerful pattern in functional programming. We will explore it in depth in the coming posts when we talk about currying and partial applications.
First class functions are the cornerstones of any functional programming language. The main point that you should take away from our discussion about first class functions is that functions can be assigned as constants, variables, placed as array elements and even set as values of keys on an object. Additionally, (and most importantly ?!) functions can be returned to and from functions — just like any other data type!
If you’re passionate about Front End development, check out the JavaScript Works job-board here!
Ground Floor, Verse Building, 18 Brunswick Place, London, N1 6DZ
108 E 16th Street, New York, NY 10003
Join over 111,000 others and get access to exclusive content, job opportunities and more!