Book Image

Advanced JavaScript

By : Zachary Shute
Book Image

Advanced JavaScript

By: Zachary Shute

Overview of this book

If you are looking for a programming language to develop flexible and efficient applications, JavaScript is an obvious choice. Advanced JavaScript is a hands-on guide that takes you through JavaScript and its many features, one step at a time. You'll begin by learning how to use the new JavaScript syntax in ES6, and then work through the many other features that modern JavaScript has to offer. As you progress through the chapters, you’ll use asynchronous programming with callbacks and promises, handle browser events, and perform Document Object Model (DOM) manipulation. You'll also explore various methods of testing JavaScript projects. In the concluding chapters, you'll discover functional programming and learn to use it to build your apps. With this book as your guide, you'll also be able to develop APIs using Node.js and Express, create front-ends using React/Redux, and build mobile apps using React/Expo. By the end of Advanced JavaScript, you will have explored the features and benefits of JavaScript to build small applications.
Table of Contents (9 chapters)

Introducing Arrow Functions


Arrow functions, or Fat arrow functions, are a new way to create functions in ECMAScript 6. Arrow functions simplify function syntax. They are called fat arrow functions because they are denoted with the characters =>, which, when put together look like a fat arrow. Arrow functions in JavaScript are frequently used in callback chains, promise chains, array methods, in any situation where unregistered functions would be useful.

The key difference between arrow functions and normal functions in JavaScript is that arrow functions are anonymous. Arrow functions are not named and not bound to an identifier. This means that an arrow function is created dynamically and is not given a name like normal functions. Arrow functions can however be assigned to a variable to allow for reuse.

When creating an arrow function, all we need to do is remove the function keyword and place an arrow between the function arguments and function body. Arrow functions are denoted with the following syntax:

( arg1, arg2, ..., argn ) => { /* Do function stuff here */ }

Snippet 1.13: Arrow function syntax

As you can see from the preceding syntax, arrow functions are a more concise way of writing functions in JavaScript. They can make our code more concise and easier to read.

Arrow function syntax can also vary, depending on several factors. Syntax can vary slightly depending on the number of arguments passed in to the function, and the number of lines of code in the function body. The special syntax conditions are outlined briefly in the following list:

  • Single input argument

  • No input arguments

  • Single line function body

  • Single expression broken over multiple lines

  • Object literal return value

Exercise 3: Converting Arrow Functions

To demonstrate the simplified syntax by converting a standard function into an arrow function, perform the following steps:

  1. Create a function that takes in parameters and returns the sum of the two parameters. Save the function into a variable called fn1.

  2. Convert the function you just created to an arrow function and save into another variable called fn2.

    To convert the function, remove the function keyword. Next, place an arrow between the function arguments and the function body.

  3. Call both functions and compare the output.

Code

index.js:
const fn1 = function( a, b ) { return a + b; };
const fn2 = ( a, b ) => { return a + b; };
console.log( fn1( 3 ,5 ), fn2( 3, 5 ) );

Snippet 1.14: Calling the functions

Outcome

Figure 1.5: Comparing the function's output

You have successfully converted normal functions into arrow functions.

Arrow Function Syntax

If there are multiple arguments being passed in to the function, then we create the function with the parentheses around the arguments as normal. If we only have a single argument to pass to the function, we do not need to include the parentheses around the argument.

There is one exception to this rule, and that is if the parameter is anything other than a simple identifier. If we include a default value or perform operations in the function arguments, then we must include the parentheses. For example, if we include a default parameter, then we will need the parentheses around the arguments. These two rules are shown in the following code:

// Single argument arrow function
arg1 => { /* Do function stuff here */ }

// Non simple identifier function argument
( arg1 = 10 ) => { /* Do function stuff here */ }

Snippet 1.15: Single argument arrow function

If we create an arrow function with no arguments, then we need to include the parentheses, but they will be empty. This is shown in the following code:

// No arguments passed into the function
( ) => { /* Do function stuff here */ }

Snippet 1.16: No argument

Arrow functions can also have varied syntax, depending on the body of the function. As expected, if the body of the function is multiline, then we must surround it with curly braces. However, if the body of the function is a single line, then we do not need to include the curly braces around the body of the function. This is shown in the following code:

// Multiple line body arrow function
( arg1, arg2 ) => { 
  console.log( `This is arg1: ${arg1}` );
  console.log( `This is arg2: ${arg2}` );
  /* Many more lines of code can go here */
}

// Single line body arrow function
( arg1, arg2 ) => console.log( `This is arg1: ${arg1}` )

Snippet 1.17: Single line body

When using arrow functions, we may also exclude the return keyword if the function is a single line. The arrow function automatically returns the resolved value of the expression on that line. This syntax is shown in the following code:

// With return keyword - not necessary
( num1, num2 ) => { return ( num1 + num2 ) }
// If called with arguments num1 = 5 and num2 = 5, expected output is 10

// Without return keyword or braces
( num1, num2 ) => num1 + num2
// If called with arguments num1 = 5 and num2 = 5, expected output is 10

Snippet 1.18: Single line body when value is returned

Since arrow functions with single expression bodies can be defined without the curly braces, we need special syntax to allow us to split the single expression over multiple lines. To do this, we can wrap the multi-line expression in parentheses. The JavaScript interpreter sees that the line are wrapped in parentheses and treats it as if it were a single line of code. This is shown in the following code:

// Arrow function with a single line body
// Assume numArray is an array of numbers
( numArray ) => numArray.filter( n => n > 5).map( n => n - 1 ).every( n => n < 10 )

// Arrow function with a single line body broken into multiple lines
// Assume numArray is an array of numbers
( numArray ) => (
  numArray.filter( n => n > 5)
          .map( n => n - 1 )
          .every( n => n < 10 )
)

Snippet 1.19: Single line expression broken into multiple lines

If we have a single line arrow function returning an object literal, we will need special syntax. In ES6, scope blocks, function bodies, and object literals are all defined with curly braces. Since single line arrow functions do not need curly braces, we must use the special syntax to prevent the object literal's curly braces from being interpreted as either function body curly braces or scope block curly braces. To do this, we surround the returned object literal with parentheses. This instructs the JavaScript engine to interpret curly braces inside the parentheses as an expression instead of a function body or scope block declaration. This is shown in the following code:

// Arrow function with an object literal in the body
( num1, num2 ) => ( { prop1: num1, prop2: num2 } ) // Returns an object

Snippet 1.20: Object literal return value

When using arrow functions, we must be careful of the scope that these functions are called in. Arrow functions follow normal scoping rules in JavaScript, with the exception of the this scope. Recall that in basic JavaScript, each function is assigned a scope, that is, the this scope. Arrow functions are not assigned a this scope. They inherit their parent's this scope and cannot have a new this scope bound to them. This means that, as expected, arrow functions have access to the scope of the parent function, and subsequently, the variables in that scope, but the scope of this cannot be changed in an arrow function. Using the .apply(), .call(), or .bind() function modifiers will NOT change the scope of an arrow function's this property. If you are in a situation where you must bind this to another scope, then you must use a normal JavaScript function.

In summary, arrow functions provide us with a way to simplify the syntax of anonymous functions. To write an arrow function, simply omit the function keyword and add an arrow between the arguments and function body.

Special syntax can then be applied to the function arguments and body to simplify the arrow function even more. If the function has a single input argument, then we can omit the parentheses around it. If the function body has a single line, we can omit the return keyword and the curly braces around it. However, single-line functions that return an object literal must be surrounded with parentheses.

We can also use parentheses around the function body to break a single line body into multiple lines for readability.

Exercise 4: Upgrading Arrow Functions

To utilize the ES6 arrow function syntax to write functions, perform the following steps:

  1. Refer to the exercises/exercise4/exercise.js file and perform the updates in this file.

  2. Convert fn1 with basic ES6 syntax.

    Remove the function keyword before the function arguments. Add an arrow between the function arguments and function body.

  3. Convert fn2 with single statement function body syntax.

    Remove the function keyword before the function arguments. Add an arrow between the function arguments and function body.

    Remove the curly braces ({}) around the function body. Remove the return keyword.

  4. Convert fn3 with Single input argument syntax.

    Remove the function keyword before the function arguments. Add an arrow between the function arguments and function body.

    Remove the parentheses around the function input argument.

  5. Convert fn4 with no input argument syntax.

    Remove the function keyword before the function arguments. Add an arrow between the function arguments and function body.

  6. Convert fn5 with object literal syntax.

    Remove the function keyword before the function arguments. Add an arrow between the function arguments and function body.

    Remove the curly braces ({}) around the function body. Remove the return keyword.

    Surround the returned object with parentheses.

Code

index.js:
let fn1 = ( a, b ) => { … };
let fn2 = ( a, b ) => a * b;
let fn3 = a => { … };
let fn4 = () => { … };
let fn5 = ( a ) => ( …  );

Snippet 1.21: Arrow function conversion

Outcome

Figure 1.6: Converting the function's output

You have successfully utilized the ES6 arrow function syntax to write functions.

In this section, we introduced arrow functions and demonstrated how they can be used to greatly simplify function declaration in JavaScript. First, we covered the basic syntax for arrow functions: ( arg1, arg2, argn ) => { /* function body */ }. We proceeded to cover the five special syntax cases for advanced arrow functions, as outlined in the following list:

  • Single input argument: arg1 => { /* function body */ }

  • No input arguments: ( ) => { /* function body */ }

  • Single line function body: ( arg1, arg2, argn ) => /* single line */

  • Single expression broken over multiple lines: ( arg1, arg2, argn ) => ( /* multi line single expression */ )

  • Object literal return value: ( arg1, arg2, argn ) => ( { /* object literal */ } )