Note
The chapter examples and library source code are in branch chap02. The repo’s URL is: https://github.com/antoaravinth/functional-es6.git
Once checkout the code, please checkout branch chap02:
...
git checkout -b chap02 origin/chap02
...
For running the codes, as before run:
...
npm run playground
...
In the previous chapter we saw what functional programming is all about. We saw how functions in the software world are nothing but Mathematical functions. We spent a lot of time discussing how Pure functions can bring us huge advantages such as parallel code execution, being cachable, etc. We are now convinced that functional programming is all about functions.
In this chapter we are going to see how functions in JavaScript can be used. We will be looking at the latest JavaScript version ES6. This chapter will be a refresher on how to create functions, call them, and pass arguments in ES6 but not explaining all the features of ES6. But that’s not the goal of this book. I strongly recommend you to try all the code snippets in the book to get a gist of how to use ES6 functions (more precisely we will be working on arrow functions).
Once we have a solid understanding of how to use functions, we will be turning our focus onto seeing how to run the ES6 code in our system. As of today, browsers don’t support all features of ES6. In order to tackle that, we will be using a tool called Babel. At the end of the chapter we will be starting our groundwork on creating a functional library. For this purpose we will be using a node project that will be set up using Babel-Node tool to run our ES6 codes in your system!
ECMAScript A Bit of History
ECMASCRIPT is a specification of JavaScript, which is maintained by Ecma International in ECMA-262 and ISO/IEC 16262. There are three versions of ECMASCRIPT; to be more specific they are the following:
ECMAScript 1 – was the very first version of JavaScript language, which was released in the year 1997.
ECMAScript 2 – is the second version of the JavaScript language, which contains very minor changes with respect to the previous versions. This version got released in the year 1998.
ECMAScript 3 – this version introduced several features, which got released in the year 1999.
ECMAScript 5 – this version is supported by almost all of the browsers today. This is the version that had introduced strict mode into the language. It was released in the year 2009. ECMAScript 5.1 also released with minor corrections in June 2011.
ECMAScript 6 – this version is where JavaScript has seen many changes like introducing classes, Symbols, Arrow Functions, and Generators, etc. It is not yet supported by many browsers today.
We will be referring to ECMAScript as ES6 in this book. So these terms are interchangeable.
Creating and Executing Functions
In this section we are going to see how to create and execute functions in several ways in ES6. This section is going to be long and interesting!
Since many browsers do not yet support ES6 today, we want to find a way to run ES6 code smoothly. Meet Babel. Babel is a transpiler, which can convert ES6 code into valid ES5 code (note that in our history section, we mentioned ES5 code can be run in all browsers today). By converting the code into ES5 the developers have a way of seeing and using the features of ES6 without any problem. Using Babel, we can run all the code samples that are presented in this book. Installation of Babel is covered in Appendix A. Kindly refer to this appendix and install Babel before we begin.
Now having installed Babel, let’s get our hands dirty by seeing our first simple function in ES6.
First Function
We will define our first simple function in ES6. The simplest function one can write in ES6 is as follows (Listing 2-1):
Listing 2-1. A Simple Function
() => "Simple Function"If you try to run this function in babel-repl, you can see the result as:
[Function]Note
It’s not necessary that you run the code samples in the Babel world. If you’re using the latest browser and you’re sure that it supports ES6 (you can check it here: https://kangax.github.io/compat-table/es6/ ), then you can use your browser console to run the code snippets. After all it’s a matter of choice. And if you’re running the code, say in Chrome, for example, the above code snippet should give you this result:
function () => "Simple Function"The point to note over here is the results might differ in showing the function representation based on where you’re running the code snippets.
Yeah, that’s it – we have function! Take a moment to analyze the above function. Let’s split them:
() => "Simple Function"//where () represents function arguments//=> starts the function body/definition//content after => are the function body/definition.
In ES6 we can skip the function keyword to define functions. You can see we have used => operator to define the function body. Functions created this way in ES6 are called Arrow Functions. We will be using Arrow functions throughout the book.
Now that the function is defined, we can execute it to see the result. Oh wait! The function we have created doesn’t have a name. Then how do I call it?
Note
Functions that don’t have names are called Anonymous functions. We will understand the usage of anonymous functions in the functional programming paradigm, when seeing Higher Order functions in the next chapter.
Let’s assign a name for it as shown in Listing 2-2:
Listing 2-2. A Simple Function with Name
var simpleFn = () => "Simple Function"Since we now have access to the function simpleFn we can use this reference to execute the function:
simpleFn()//returns "Simple Function" in the console
That’s great! We have created a function and also executed it in ES6.
We can see how the same function looks alike in ES5. We can use babel to convert our code into ES5, using the following command:
babel simpleFn.js --presets babel-preset-es2015 --out-file script-compiled.js This will generate the file called the script-compiled.js in your current directory. Now open up the generated file in your favorite editor:
"use strict";var simpleFn = function simpleFn() {return "Simple Function";};
That’s our equivalent code in ES5! You can sense how it’s much easier and concise to write functions in ES6! Don’t you? There are two important points to note in the converted code snippets. We will discuss them one after the other.
Strict Mode
In this section we will discuss “Strict Mode ” in JavaScript. We’ll see its benefits and why one should prefer “Strict Mode.”
You can see that the converted code runs in the strict mode, as shown here:
"use strict";var simpleFn = function simpleFn() {return "Simple Function";};
Strict modes have nothing to do with ES6, but discussing them here is the right choice. As we have already discussed in the ECMAScript History section, strict mode was introduced to the JavaScript language at ES5.
Simply put, strict mode is a restricted variant of JavaScript. The same JavaScript code that is running in strict mode can be semantically different from the code, which is not using strict. All the code snippets, which don’t add the use strict in their js files, are going to be in non-strict mode.
Why should we use strict mode? What are the advantages? There are many advantages of using strict mode style in the world of JavaScript. One simple thing is if you are defining a variable in global state (i.e., without specifying var command) like this:
"use strict";globalVar = "evil"
In strict mode it’s going to be an error! That’s a good catch for our developers, because global variables are very evil in JavaScript! However if the same code were run in non-strict mode, then it wouldn’t have complained about the error!
Now as you can guess, the same code in JavaScript can produce different results whether you’re running in strict or non-strict mode. Since strict mode is going to be very helpful for us, we will leave Babel to use strict mode while transpiling our ES6 codes.
Note
We can place use stricts in either the beginning of your JavaScript file, in which case it’s going to apply its check for the full functions defined in the particular file. Or else you can use strict mode only to specific functions. In that case, strict mode will be applied only to that particular function, leaving other function behaviors in non-strict mode. More on MDN ( https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Strict_mode )
Return Statement Is Optional
In ES5 converted code snippet, we saw that Babel adds the return statement in our simpleFn.
"use strict";var simpleFn = function simpleFn() {return "Simple Function";};
Where as in our real ES6 code, we didn’t specify any return statement:
var simpleFn = () => "Simple Function"Thus in ES6, if you have a function with only a single statement then it implicitly means that it returns the value. What about multiple statement functions? How we are going to create them in ES6?
Multiple Statement Functions
Now we are going to see how to write multiple statement functions in ES6. Let’s make our simpleFn a bit more complicated as follows in Listing 2-3:
Listing 2-3. Multistatement Function
var simpleFn = () => {let value = "Simple Function"return value;} //for multiple statement wrap with { }
Run the above function, and you will get the same result as before. But here we have used the multiple arguments to achieve the same behavior. Apart from that, you could notice that we have used let a keyword define our value variable. The let keyword is new to the JavaScript keyword family. The let keyword allows you to declare variables that are limited to a particular scope of block! This is unlike the var keyword that defines the variable globally to a function regardless of the block in which it’s defined.
To make the point concrete, we can write the same function with var and the let keyword, inside an if block as shown in Listing 2-4.
Listing 2-4. SimpleFn with var and let Keywords
var simpleFn = () => { //function scopeif(true) {let a = 1;var b = 2;console.log(a)console.log(b)} //if block scopeconsole.log(b) //function scopeconsole.log(a) //function scope}
Running this function gives the following output:
122Uncaught ReferenceError: a is not defined(...)
As you can see from the output, the variable declared via let keyword is accessible only within the if block not outside the block. As you notice, JavaScript throws the error when we access the variable a variable outside the block! But whereas the variable declared with var when doesn’t act that way. Rather, it declares the variable scope for the whole function. That’s the reason variable b can be accessed outside the if block.
Since block scope is very much needed going further, we will be using the let keyword for defining variables throughout the book. Now let’s see how to create a function with arguments as the final section.
Function Arguments
Creating functions with arguments is the same as in ES5. Look at a quick example as follows (Listing 2-5):
Listing 2-5. Function with Argument
var identity = (value) => valueHere we create a function called identity, which takes value as its argument and returns the same. As you can see, creating functions with arguments are the same as ES5; only the syntax of creating the function is changed.
ES5 Functions Are Valid in ES6
Before we close this section, we need to make an important point clear. The functions that were written in ES5 are still valid in ES6! It’s just a small matter that ES6 has introduced Arrow functions, it but doesn’t replace the old function syntax or anything else. However we will be using ES6 functions throughout this book to showcase the functional programming approach.
Setting Up Our Project
After having an understanding of how to create Arrow functions in ES6 , we will shift our focus onto project setup in this section. We are going to set up our project as a node project and at the end of the section, we will be writing our first Functional Function. Let’s begin!
Note
Make sure you have installed node and npm by following Appendix A.
Initial Setup
In this section, we will be following a simple step-by-step guide to set up our environment. The steps are as follows:
The first step is to create a directory where our source code is going to be. Create a directory and name it whatever you want.
Go into that particular directory and run the following command from your terminal:
npm initAfter running step 2, it will be asking you a set of questions; you can provide the value you want. Once it’s done, it will create a file called pacakage.json in your current directory.
The project package.json that I have created looks like this as shown here in Listing 2-6:
Listing 2-6. Package.json Contents
{"name": "learning-functional","version": "1.0.0","description": "Functional lib and examples in ES6","main": "index.js","scripts": {"test": "echo \"Error: no test specified\" && exit 1"},"author": "Anto Aravinth @antoaravinth","license": "ISC"}
Now we need to add a few libraries, which will allow us to write ES6 code and execute them. Run the following command in the current directory:
npm install --save-dev babel-preset-es2015-node5Note
The book uses Babel version “babel-preset-es2015-node5.” It’s highly possible that this specific version may be outdated by the time you read this text. You are free to install the latest version and everything should work smoothly. However, in the context of the book, we will be using the specified version.
The above command downloads the babel package called ES2015-Node5; the main aim of this package is to allow ES6 code to run on Node Js platform. The reason is that Node Js, at the time of writing this book; is not fully compatible with ES6 features.
Once the above command is run, you will be able to see a folder called node_modules created in the directory, which has the babel-preset-es2015-node5 folder.
Since we have used --save-dev while installing, npm does add the corresponding babel dependencies to our package.json. Now if you open your package.json, it looks like this:
Listing 2-7. After Adding the devDependencies
{"name": "learning-functional","version": "1.0.0","description": "Functional lib and examples in ES6","main": "index.js","scripts": {"test": "echo \"Error: no test specified\" && exit 1"},"author": "Anto Aravinth @antoaravinth>","license": "ISC","devDependencies": {"babel-preset-es2015-node5": "^1.2.0","babel-cli": "^6.23.0"}}
Now that this is in place, we can go ahead and create two directories called lib and functional-playground. So now your directory looks like the following:
learning-functional- functional-playground- lib- node_modules- babel-preset-es2015-node5/*- package.json
Now we are going to put all our functional library code into lib and use functional-playground to play and understand our functional techniques.
Our First Functional Approach to the Loop Problem
Imagine we have to iterate through the array and print the data to the console. How do we achieve this in JavaScript?
Listing 2-8. Looping an Array
var array = [1,2,3]for(i=0;i<array.length;i++)console.log(array[i])
As we have already discussed in Functional Programming in Simple Terms, Chapter 1, abstracting the operations into functions is one of the pillars of functional programming. So let’s go and abstract this operation into function, so that we can reuse it any time we need to rather than repeating ourselves in telling “how” to iterate the loop.
Create a file called es6-functional.js in lib directory. Our directory structure looks like this:
learning-functional- functional-playground- lib- es6-functional.js- node_modules- babel-preset-es2015-node5/*- package.json
Now with that file in place, go ahead and place the below content into that file:
Listing 2-9. forEach Function
const forEach = (array,fn) => {let i;for(i=0;i<array.length;i++)fn(array[i])}
Note
For now don’t worry about how this function works. We are going to see how Higher-Order functions work in JavaScript in the next chapter and provide loads of examples.
You might notice that we have started with a keyword const for our function definition. This keyword is part of ES6, which makes the declaration constant. For example, if someone tries to reassign the variable with the same name like this:
forEach = "" //making your function as string!The above code will throw an error like this:
TypeError: Assignment to constant variable.This will prevent it from being accidently reassigned! Now we’ll go and use the above created function to print all the data of the array to the console. In order to do that, create a file called play.js function in functional-playground directory. So now the current file looks like:
learning-functional- functional-playground- play.js- lib- es6-functional.js- node_modules- babel-preset-es2015-node5/*- package.json
We will call the forEach in our play.js file. But how are we are going to call this function, which resides in a different file?
Gist on Exports
ES6 also introduced the concept called modules. ES6 modules are stored in files. In our case we can think of es6-functional.js file itself as a module. Along with the concept of modules came imports and exports statements. In our running example, we have to export the forEach function so that others can use them. So that we can change the following code into
Listing 2-10. Exporting forEach Functionconst forEach = (array,fn) => {
let i;for(i=0;i<array.length;i++)fn(array[i])}export default forEach
in our es6-functional.js file.
Gist on Imports
Now that we have exported our function as you can see in Listing 2-10, let’s go and consume it via import! Open the file play.js and add the following into it as shown in Listing 2-11:
Listing 2-11. Importing forEach Function
import forEach from '../lib/es6-functional.js'The above line tells JavaScript to import the function called forEach from es6-functional.js. Now the function is available to the whole file with the name forEach. Now add the code into play.js like this as shown here in Listing 2-12:
Listing 2-12. Using the Imported forEach function
import forEach from '../lib/es6-functional.js'var array = [1,2,3]forEach(array,(data) => console.log(data)) //refereing to imported forEach
Running the Code Using Babel-Node
Let’s run our play.js file. Since we are using ES6 in our file, we have to use Babel-Node to run our code. Babel-Node is used to transpile our ES6 code and run it on Node js. Babel-Node should be installed along with babel-cli.
Note
Babel-node will be available in the terminal, only if you have installed babel-cli globally. Kindly refer to Appendix A for installing cli globally.
So from our project root directory, we can call the babel-node like this:
babel-node functional-playground/play.js --presets es2015-node5The above command tells us that our play.js file should be transpiled with es2015-node5 and run into node js. This should give the output as follows:
123
Hurray! Now we have abstracted out for logic into a function. Imagine you want to iterate and print the array contents with multiples of 2. How will we do it? Super simple – reuse our forEach:
forEach(array,(data) => console.log(2 * data))which will print the output as expected!
Note
We will be using this pattern throughout the book. We will be discussing the problem with an imperative approach. Then will go ahead and implement our functional techniques and capture them in a function into es6-functional.js. And then use that to play around in play.js file!
Creating Script in Npm
We have seen how to run our play.js file. But it’s lot to type! Each time we need to run the following:
babel-node functional-playground/play.js --presets es2015-node5Rather than this, we can bind the following command to our npm script. We will change the package.json accordingly:
Listing 2-13. Adding npm Scripts to package.json
{"name": "learning-functional","version": "1.0.0","description": "Functional lib and examples in ES6","main": "index.js","scripts": {"playground" : "babel-node functional-playground/play.js --presets es2015-node5"},"author": "Anto Aravinth @antoaravinth","license": "ISC","devDependencies": {"babel-preset-es2015-node5": "^1.2.0"}}
Now we have added the babel-node command to scripts. So we can run our playground file (node functional-playground/play.js) as follows:
npm run playgroundwhich will run the same as before.
Running the Source Code from Git
Whatever we are discussing in the chapter will go into a git repository ( https://github.com/antoaravinth/functional-es6 ). You can clone them into your system using git like this:
git clone https://github.com/antoaravinth/functional-es6.gitOnce you clone the repo, you can move into a specific chapter source code branch. Each chapter has its own branch in the repo. For example, in order to see the code samples used in Chapter 2, then you need to do this:
git checkout -b chap02 origin/chap02Once you check out the branch, you can run the playground file as before!
Summary
In this chapter, we have spent a lot of time in seeing how to use functions in ES6 modes. We saw how Arrow functions are being introduced and used in ES6. We have taken the advantage of Babel tools for running our ES6 code seamlessly in our Node platform. We also created our project as a Node project. In our node project, we saw how to use Babel Node to convert the ES6 code and run them in node environment using presets. We also saw how to download the book source code and run it. With all these techniques under our belt, in the next chapter we will be focusing on what Higher-Order Functions mean!