© Anto Aravinth, Srikanth Machiraju 2018
Anto Aravinth and Srikanth MachirajuBeginning Functional JavaScripthttps://doi.org/10.1007/978-1-4842-4087-8_2

2. Fundamentals of JavaScript Functions

Anto Aravinth1  and Srikanth Machiraju2
(1)
Chennai, Tamil Nadu, India
(2)
Hyderabad, Andhra Pradesh, India
 

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, and more. 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, ES7/8. This chapter is a refresher on how to create functions, call them, and pass arguments as defined in ES6 and later versions. That’s not the goal of this book, though. We strongly recommend that you try all the code snippets in the book to get a gist of how to use 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 to seeing how to run the ES8 code in our system. As of today, browsers don’t support all features of ES8. To tackle that, we will be using a tool called Babel. At the end of the chapter we will be starting our groundwork for creating a functional library. For this purpose, we will be using a node project that will be set up using the Babel-Node tool to run our code in your system.

Note

The chapter examples and library source code are in branch chap02. The repo’s URL is https://github.com/antsmartian/functional-es8.git

Once you check out the code, please check out branch chap02:

...

git checkout -b chap02 origin/chap02

...

For running the codes, as before run:

...

npm run playground

...

ECMAScript: A Bit of History

ECMAScript is a specification of JavaScript, which is maintained by ECMA International in ECMA-262 and ISO/IEC 16262. Here are the versions of ECMAScript:
  1. 1.

    ECMAScript 1 was the very first version of the JavaScript language, released in 1997.

     
  2. 2.

    ECMAScript 2 is the second version of the JavaScript language, which contains very minor changes with respect to the previous version. This version was released in 1998.

     
  3. 3.

    ECMAScript 3 introduced several features and was released in 1999.

     
  4. 4.

    ECMAScript 5 is supported by almost all browsers today. This is the version that introduced strict mode into the language. It was released in 2009. ECMAScript 5.1 was released with minor corrections in June 2011.

     
  5. 5.

    ECMAScript 6 introduced many changes, including classes, symbols, arrow functions, generators, and so on.

     
  6. 6.

    ECMAScript 7 and 8 have new concepts like async await, SharedArrayBuffer, trailing commas, Object.entries, and so on.

     

We refer to ECMAScript as ES7 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 JavaScript. This section is going to be long and interesting as well. Because many browsers do not yet support ES6 or higher versions, we want to find a way to run our code smoothly. Meet Babel, a transpiler that can convert the latest code into valid ES5 code (note that in our history section, we mentioned ES5 code can be run in all browsers today). Converting the code into ES5 gives developers a way of seeing and using the features of the latest version of ECMAScript without any problem. Using Babel, we can run all the code samples that are presented in this book.

After you have installed Babel, we can get our hands dirty by seeing our first simple function.

First Function

We define our first simple function here. The simplest function one can write in ES6 or higher versions is given in Listing 2-1.
() => "Simple Function"
Listing 2-1

A Simple Function

If you try to run this function in babel-repl, you will see this result:
[Function]

Note

It’s not necessary to run the code samples in the Babel world. If you’re using the latest browser and you’re sure that it supports the latest version of ECMAScript, then you can use your browser console to run the code snippets. After all it’s a matter of choice. If you’re running the code, say in Chrome, for example, Listing 2-1 should give you this result:

function () => "Simple Function"

The point to note here is the results might differ in showing the function representation based on where you’re running the code snippets.

That’s it: We have a function. Take a moment to analyze this function. Let’s split them:
() => "Simple Function"
//where () represents function arguments
//=> starts the function body/definition
//content after => are the function body/definition.

We can skip the function keyword to define functions. You can see we have used the => operator to define the function body. Functions created this way are called arrow functions. We use 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. How do we 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 Chapter 3.

Let’s assign a name for it as shown in Listing 2-2.
var simpleFn = () => "Simple Function"
Listing 2-2

A Simple Function with a Name

Because we now have access to the function simpleFn we can use this reference to execute the function:
simpleFn()
//returns "Simple Function" in the console
Now we have created a function and also executed it. 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 script-compiled.js in your current directory. Now open 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 is much easier and more concise to write functions in the latest versions. There are two important points to note in the converted code snippets. We discuss them one after the other.

Strict Mode

In this section we 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 strict mode, as shown here:
"use strict";
var simpleFn = function simpleFn() {
  return "Simple Function";
};

Strict mode has nothing to do with the latest versions, but discussing it here is appropriate. As we have already discussed, strict mode was introduced to JavaScript language with 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 mode. All the code snippets that don’t use strict in their JavaScript files are going to be in nonstrict 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 advantage occurs 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 nonstrict 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 nonstrict mode. Because strict mode is going to be very helpful for us, we will leave Babel to use strict mode while transpiling our ES8 codes.

Note

We can place use stricts in the beginning of a JavaScript file, in which case it’s going to apply its check for the full functions defined in the particular file. Otherwise, you can use strict mode only for specific functions. In that case, strict mode will be applied only to that particular function, leaving other function behaviors in nonstrict mode. For more information on this, see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Strict_mode .

Return Statement Is Optional

In the ES5 converted code snippet, we saw that Babel adds the return statement in our simpleFn.
"use strict";
var simpleFn = function simpleFn() {
  return "Simple Function";
};
In our real code, though, we didn’t specify any return statement :
var simpleFn = () => "Simple Function"

Thus here, 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?

Multiple Statement Functions

Now we are going to see how to write multiple statement functions . Let’s make our simpleFn a bit more complicated, as shown in Listing 2-3.
var simpleFn = () => {
   let value = "Simple Function"
   return value;
} //for multiple statement wrap with { }
Listing 2-3

Multistatement Function

Run this function, and you will get the same result as before. Here, though, we have used multiple arguments to achieve the same behavior. Apart from that, notice that we have used the let keyword to define our value variable. The let keyword is new to the JavaScript keyword family. It allows you to declare variables that are limited to a particular scope of block, unlike the var keyword, which defines the variable globally to a function regardless of the block in which it is 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.
var simpleFn = () => { //function scope
   if(true) {
      let a = 1;
      var b = 2;
      console.log(a)
      console.log(b)
   } //if block scope
   console.log(b) //function scope
   console.log(a) //function scope
}
Listing 2-4

SimpleFn with var and let Keywords

Running this function gives the following output:
1
2
2
Uncaught ReferenceError: a is not defined(...)

As you can see from the output, the variable declared via the let keyword is accessible only within the if block, not outside the block. JavaScript throws the error when we access a variable outside the block, whereas the variable declared with var 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.

Because block scope is very much needed going forward, 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).
let identity = (value) => value
Listing 2-5

Function with Argument

Here we create a function called identity , which takes value as its argument and returns the same. As you can see, creating functions with arguments is the same as in ES5; only the syntax of creating the function is changed.

ES5 Functions Are Valid in ES6 and Above

Before we close this section, we need to make an important point clear. The functions that were written in ES5 are still valid in the latest version(s). It’s just a small matter that newer versions have introduced arrow functions, but that doesn’t replace the old function syntax or anything else. However, we will be using arrow functions throughout this book to showcase the functional programming approach.

Setting Up Our Project

Now that we understand how to create arrow functions, we shift our focus to 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.

Initial Setup

In this section, we follow a simple step-by-step guide to set up our environment. The steps are as follows.
  1. 1.

    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.

     
  2. 2.

    Go into that particular directory and run the following command from your terminal:

     
npm init
  1. 3.

    After running Step 2, you will be asked a set of questions; you can provide the value you want. Once it’s done, it will create a file called package.json in your current directory.

     
The project package.json that we have created looks like Listing 2-6.
{
  "name": "learning-functional",
  "version": "1.0.0",
  "description": "Functional lib and examples in ES8",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "Anto Aravinth @antoaravinth",
  "license": "ISC"
}
Listing 2-6

Package.json Contents

Now we need to add a few libraries, which will allow us to write ES8 code and execute them. Run the following command in the current directory:
npm install --save-dev babel-preset-es2017-node7

Note

The book uses Babel version “babel-preset-es2017-node7.” This specific version might 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.

This command downloads the babel package called ES2017; the main aim of this package is to allow the latest ECMAScript code to run on the Node Js platform. The reason is that Node Js, at the time of writing this book, is not fully compatible with the latest features.

Once this command is run, you will be able to see a folder called node_modules created in the directory, which has the babel-preset-es2017 folder.

Because 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 Listing 2-7.
{
  "name": "learning-functional",
  "version": "1.0.0",
  "description": "Functional lib and examples",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "Anto Aravinth @antoaravinth>",
  "license": "ISC",
  "devDependencies": {
    "babel-preset-es2017-node7": "^0.5.2",
    "babel-cli": "^6.23.0"
  }
}
Listing 2-7

After Adding devDependencies

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 this:
learning-functional
  - functional-playground
  - lib
  - node_modules
    - babel-preset-es2017-node7/*
  - package.json

Now we are going to put all our functional library code into lib and use functional-playground to explore 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?
var array = [1,2,3]
for(i=0;i<array.length;i++)
    console.log(array[i])
Listing 2-8

Looping an Array

As we have already discussed in Chapter 1, abstracting the operations into functions is one of the pillars of functional programming. Let’s abstract this operation into function, so that we can reuse it any time we need to rather than repeating ourselves in telling it how to iterate the loop.

Create a file called es8-functional.js in the lib directory . Our directory structure looks like this:
learning-functional
  - functional-playground
  - lib
    - es8-functional.js
  - node_modules
    - babel-preset-es2017-node7/*
  - package.json
Now with that file in place, go ahead and place the content of Listing 2-9 into that file.
const forEach = (array,fn) => {
   let i;
   for(i=0;i<array.length;i++)
      fn(array[i])
}
Listing 2-9

forEach Function

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 the latest version, 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 preceding code will throw an error like this:
TypeError: Assignment to constant variable.
This will prevent it from being accidentally reassigned. Now we’ll go and use the created function to print all the data of the array to the console. To do that, create a file called play.js function in the functional-playground directory. So now the current file looks like this:
learning-functional
  - functional-playground
     - play.js
  - lib
    - es8-functional.js
  - node_modules
    - babel-preset-es2017-node7/*
  - package.json

We will call the forEach in our play.js file. 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 the es8-functional.js file itself as a module. Along with the concept of modules came import and export statements. In our running example, we have to export the forEach function so that others can use it. We can add the code shown in Listing 2-10 to our es8-functional.js file.
const forEach = (array,fn) => {
   let i;
   for(i=0;i<array.length;i++)
      fn(array[i])
}
export default forEach
Listing 2-10

Exporting forEach Function

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 code shown in Listing 2-11.
import forEach from '../lib/es8-functional.js'
Listing 2-11

Importing forEach Function

This line tells JavaScript to import the function called forEach from es8-functional.js. Now the function is available to the whole file with the name forEach. Now add the code into play.js as shown in Listing 2-12.
import forEach from '../lib/es8-functional.js'
var array = [1,2,3]
forEach(array,(data) => console.log(data)) //refereing to imported forEach
Listing 2-12

Using the Imported forEach Function

Running the Code Using Babel-Node

Let’s run our play.js file. Because we are using the latest version in our file, we have to use Babel-Node to run our code. Babel-Node is used to transpile our code and run it on Node js. Babel-Node should be installed along with babel-cli.

So, from our project root directory, we can call the babel-node like this:
babel-node functional-playground/play.js --presets es2017
This command tells us that our play.js file should be transpiled with es2017 and run into node js. This should give the output as follows:
1
2
3
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? Simply reuse our forEach, which will print the output as expected:
forEach(array,(data) => console.log(2 * data))

Note

We will be using this pattern throughout the book. We discuss the problem with an imperative approach and then go ahead and implement our functional techniques and capture them in a function into es8-functional.js. We then use that to play around in the play.js file!

Creating Script in Npm

We have seen how to run our play.js file, but it’s a lot to type . Each time we need to run the following:
babel-node functional-playground/play.js --presets es2015-node5
Rather than entering this, we can bind the command shown in Listing 2-13 to our npm script. We will change the package.json accordingly:
{
  "name": "learning-functional",
  "version": "1.0.0",
  "description": "Functional lib and examples",
  "main": "index.js",
  "scripts": {
    "playground" : "babel-node functional-playground/play.js --presets es2017-node7"
  },
  "author": "Anto Aravinth @antoaravinth",
  "license": "ISC",
  "devDependencies": {
    "babel-preset-es2017-node7": "^0.5.2"
  }
}
Listing 2-13

Adding npm Scripts to package.json

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 playground

This 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-es8 ). You can clone them into your system using git like this:
git clone https://github.com/antsmartian/functional-es8.git
Once 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, to see the code samples used in Chapter 2, you need to enter this:
git checkout -b chap02 origin/chap02

Once you check out the branch, you can run the playground file as before.

Summary

In this chapter, we have spent a lot of time learning how to use functions. We have taken advantage of Babel tools for running our 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 code and run them in a 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. We will explain the Async/Await features of ES7 in later chapters.