© Russ Ferguson and Keith Cirkel 2017
Russ Ferguson and Keith CirkelJavaScript Recipes10.1007/978-1-4302-6107-0_12

12. Working with Functions

Russ Ferguson and Keith Cirkel2
(1)
Ocean, New Jersey, USA
(2)
London, UK
 

How Do You Create a Function?

Problem

You want to know how many ways there are to create a function.

Solution

There are three ways to create a function, using a constructor, declaration, or expression.

The Code

//function constructor
var fun1 = new Function('name', 'return name;');
fun1('Jessica');
//function declaration
function myFun(name){
    var greeting = 'Hello ' + name;
    return greeting;
}
myFun('Danny');
//function expression
var fun3 = function(name) {
    return name;
}
fun3('Mami');
Listing 12-1.
Creating a Function

How It Works

There are the main ways to create functions. Using a constructor , a function decollation, or using a function expression. According to the ECMAScript specification, adding an identifier to a function is optional. In short, you do not need to give your function a name. This would create an anonymous function. In most cases, function declaration and function expressions are used.
When using function declaration you would provide the function name, a comma-separated list of parameters to use inside parentheses. The curly brackets {} are used to hold all the statements that are required by the function.
Function expressions can be anonymous, this is often used where functions can be passed as an argument for another function. Take a look at Chapter 11’s use of the Map function.
Functions by default return a value. If you want to return a specific value, use the return keyword. In JavaScript, every function is really a function object.

How Do You Call a Function?

Problem

Once a function has been created, you want to know how to execute it.

Solution

Executing or calling a function requires the name of the function and, if necessary, any parameters needed for the function to work.

The Code

//if a function called login was already defined
login(username, password);
console.log(sayHello(‘Peter’)); //returns Hello Peter
function sayHello(name){
    return ‘Hello ‘ + name;
}
Listing 12-2.
Calling a Function

How It Works

When functions are created, as you saw in Listing 12-1, they are not executed. Instead they wait until called upon to execute all the commands listed inside the function . The function itself must be in the same scope when it is called. The arguments that are passed over to the function can be objects including other functions.

What Are Anonymous Functions?

Problem

You want to create and execute an anonymous function.

Solution

Anonymous functions are function expressions. These expressions do not need to have a name to identify them.

The Code

document.addEventListener('DOMContentLoaded', function(){
    console.log('content loaded');
});
(function(){
    console.log('running closure');
})();
var greeting = function(name){
    return 'Hello ' + name;
};
greeting('Jenny');
Listing 12-3.
Examples of Anonymous Functions

How It Works

Anonymous functions do not have a named identifier applied to them. Because of this, the function is usually not accessible after it is created. Since functions are objects, and they can be assigned to variables and executed. If the function in that case has a name, the name of the function will not change if the function is reassigned to a new variable.
Immediately-invoked function expressions or IFFE (pronounced ‘iffy’) are functions that will automatically execute. One of the reasons for using an IFFE is to keep variables from reaching the global scope. You can also create publicly accessible methods that use privately held variables. Most use cases for anonymous functions are for closures or using a function as a argument for another function.

How Do You Create Functions Inside an Object?

Problem

You want to control the scope of your functions.

Solution

Creating functions inside an object will control the scope of the function so that it is in the scope of the object and does not fall into the global scope.

The Code

var spiderMan = {
    powers: function(){
         return 'Super Strength, Sticks to walls, Spider Sense';
    },
    realName: function(){
         return 'Peter Parker';
       }
}
//call the function
spiderMan.powers() //returns 'Super Strength, Sticks to walls, Spider Sense
Listing 12-4.
Creating Functions Inside an Object Literal

How It Works

Functions inside an object are assigned to a property of the object. This relationship is how object methods are created. When used inside a method, the property name is given first followed by a colon, then the function follows with any needed properties.
The scope that a function can then have is limited to the object scope . This will prevent the function from being part of the global scope. In order to call the function, the object is referenced first then the property that contains the function is referenced.

How Do You Return a Value from a Function?

Problem

You want a function to return a value.

Solution

The return statement will return values from a function.

The Code

function sayGoodnight1(name){
   return //function stops executing here
   'Goodnight ' + name;
}
function sayGoodnight2(name){
   return 'Goodnight ' + name;  //returns full statement
}
console.log(sayGoodnight1('Gracie'));
console.log(sayGoodnight2('Gracie'));
Listing 12-5.
Returning Values from Functions

How It Works

The return statement stops executing any of the statement inside a function and specifies what value to return. The default value is undefined if no other value is returned. Return is also subject to automatic semicolon insertion (ASI) ; there cannot be any line termination after a return statement. The browser will not execute any command after the return statement and will return undefined.

How Are Parameters Defined in a Function?

Problem

You need to know if the parameters defined in the function have values when executed.

Solution

Prior to ES6, parameters had a value of undefined. Parameters can now have default values.

The Code

//before ES6, checking if a property has a value
function doMath(num1, num2){
   var num2 = typeof num2 !== 'undefined' ? num2: 10;
   return num1 + num2;
}
console.log(doMath(1)); //returns 11
console.log(doMath(1,4)); //returns 5
//using ES6 default properties
function ES6DoMath(num1, num2 = 10){
   return num1 + num2;
}
console.log(ES6DoMath(1)); //returns 11
console.log(ES6DoMath(1,4)); //returns 5
function doCount(first, second = first + 1, third = second + 1){
   return [first, second, third];
}
console.log(doCount(1)); //returns [1,2,3]
Listing 12-6.
Checking If a Parameter Has a Value in Before ES6 and After

How It Works

Up until ES6 properties, had a value of undefined if a value was not passed when the function was called. Default properties are not restricted to strings or numbers. Objects, arrays, and functions can be used as default values. One of the values that could be passed over is undefined the result would be the same as not passing a value. This would be different than passing null. Using the previous example, the browser will return 1 and not 11 if null was passed.
Properties can also be evaluated at call time. This would give you the ability to assign a function as the default property and return the result.
Properties can also be chained together. In the last example, the value of the second property is a combination of the first property and the second’s default value . The value of the third property follows the same pattern. When returned as an array, the values are in sequence.

How Does Using Rest Parameters Allow Unlimited Number of Parameters in a Function?

Problem

You want to pass parameters to a function but don’t know how many you will need.

Solution

If the last parameter of a function is prefixed with , all values that are passed to it will be part of an array.

The Code

function daysOfTheWeek(...weekdays){
   return weekdays[2];
}
console.log(daysOfTheWeek('Monday', 'Tuesday', 'Wednesday'));  //returns Wednesday
Listing 12-7.
Using Rest Parameters on a Function

How It Works

Using rest parameters is similar to using the arguments object . However, there are some important differences. The arguments object is not a real array. This means that methods like map, sort, and pop will not work. The values of the arguments object would have to be converted into a real array first. The arguments object also returns all arguments sent to a function. Rest parameters only handle arguments that are not mapped to a name in the function. The rest parameters do not have the same methods that the arguments object does; for example callee is not available.

Can You Use Object Destructuring with Parameters of a Function?

Problem

You want to use object destructuring to extract properties of an object.

Solution

ES6 does support object destructuring with parameters.

The Code

function es5GetName(myObj){
   var name = myObj.name;
   console.log(name);
}
es5GetName({name: 'Bruce Banner'});
function getName({name}){
   console.log(name);
}
getName({name: 'Bruce Banner'}); //returns Bruce Banner
Listing 12-8.
Using Object Destructuring with a Function

How It Works

Object destructuring allows you to map variable to properties of an object. Most examples show the values of arrays being mapped to variables. Both examples in this section produce the same results. The main difference with the second one is that you can explicitly access the property then use it a variable within the function. If curly braces were wrapped around the variable, an object would return with the same name/value pair and not just the value.

How Do You Call Methods from an Object’s Parent?

Problem

You want to use a method that is not defined in the current object but in the object’s parent.

Solution

The super keyword can be used to call a function on an object’s parent.

The Code

class Ship{
        constructor(name, type, color){
        this.name = name;
        this.type = type;
        this.color = color;
        }
        shipName(){
           return 'I am ' + this.name;
        }
        shipType(){
           return  'I am type: ' + this.type;
        }
        shipColor(){
           return  'My color is ' + this.color;
        }
}
class SpaceShip extends Ship{
      constructor(type, name, color){
          super(type, name, color)
      }
      spaceShipName(){
          return super.shipName();
      }
      spaceShipType(){
          return super.shipType();
      }
      spaceShipColor(){
          return super.shipColor();
      }
}
var planetExpress = new SpaceShip('Planet Express Ship', 'Delivery Ship' ,'Green');
console.log(planetExpress.spaceShipName()); //returns I am Planet Express Ship
console.log(planetExpress.shipType());  //return I am type: 'Delivery Ship
console.log(planetExpress.spaceShipColor()); // returns My color is Green
Listing 12-9.
Using the Super Keyword to Call Methods Defined in the Parent Object

How It Works

The super keyword gives you the ability to reference properties or methods that have been created in the parent object. In the previous example, the parent class is called Ship and the other class SpaceShip extends Ship to that make it the parent class. At this point if you were to try to access elements of the parent class you would generate a ReferenceError.
In order to access properties and methods of the parent class, the super keyword must be called first. When the call is made it will execute the parent’s constructor. This also gives you the ability to pass any parameters to the parent class that may be necessary. After that, all properties can be referenced using the this keyword.

How Does the Keyword This Work Inside a Function?

Problem

How does the keyword this behave compared to other languages?

Solution

The behavior of the keyword this is generally set by the context in which it is called.

The Code

console.log(this); //returns Window
function globalFunction(){
    return this;
}
console.log(globalFunction()); //returns Window
console.log(window.globalFunction());
function globalStrictFunction(){
    'use strict'
return this;
}
console.log(globalStrictFunction());
console.log(window.globalStrictFunction());
function saySomething(){
    return this.something;
}
var phrase = saySomething.bind({something: 'Brothers! Sisters!'});
console.log(saySomething()); //returns undefined
console.log(phrase());  //returns Brothers! Sisters!
function useCallFunction(){
    return this.greeting;
}
var greetingObj = {greeting: 'Hello, Mr. Robot'};
console.log(useCallFunction.call(greetingObj));
console.log(useCallFunction.apply(greetingObj));
document.getElementById('myButton').addEventListener('click', function(e){
    console.log(this); //<button id="myButton">Click Me</button>
});
var globalArrayFunction = () => this;
console.log(globalArrayFunction());  //returns Window
var micCheck = {
    isThisOn: function(){
    return (() => this);
    }
}
var returnedFunction = micCheck.isThisOn();
console.log(returnedFunction()); //returns Object
var theNumber = {p: 42};
    function magicNumber(){
        return this.p;
 }
theNumber.theMagicNumber = magicNumber;
console.log(theNumber.theMagicNumber()) //returns 42
Listing 12-10.
The Different Ways This Can Be Used in JavaScript

How It Works

In order to understand all the different ways this can change, let’s look at it step by step. The value of the keyword this is assigned during a function call. So depending on the how the function is called, the value may be different.
First let’s talk about the global context . If you were to just print out the value of this in the console in an otherwise blank JavaScript file, it would refer to the Window object.
When returning this from a function call, its value is also Window. In this instance, the function is part of the global scope, which means you can also call this same function this way: window.globalFunction() . In either case the result would be the same.
In the earlier examples we are not using strict mode . Strict mode is a more restricted version of JavaScript that is designed to have different semantics. If you were to use strict mode at the top of the page, the first and second results would return undefined.
Strict mode can also be defined on the function level. Before all other statements add use strict to run the function in strict mode. When using the globalStrictFunction the result of this is undefined. The reason you receive undefined is that this keeps the value of whatever it was set to when the function is being executed.

Using the Bind Method on a Function

Using this method on a function creates a new function called a bound function (BF) . The value of this is set to the value that is provided in the first argument. In the following example, the function saySomething returns a property called something. On its own it would return undefined since there isn’t a variable in the function called something. When using the bind method, we provide an object with the property something. So the object becomes bound to the function and the property something now has a value.

Using Call and Apply on a Function

Using the call and apply methods on a function is similar to using bind, where you define the object that the keyword this is bound to. In the previous example, the call method passes an object over and the function uses the properties of that object to return some values. If you’re using the apply method, you would get the same results.

Using an Event Handler

If the function that is being executed is from an event handler, the value of this is set to the element that fired the event. The same is true if the event is fired from a inline event.

Using Arrow Functions

Arrow function expressions give you the ability to create functions just like a function expression but with less code. They start with the list of parameters, the arrow pointing to the statement that needs to be executed. If using this in a global context, the Window object would return. It is also the case if the function were to be called as the method of another object, or if the call or bind methods were used. This lets you know that the value of this will be set to the execution context. For example, if arrow functions were used inside an object, the result of this would be the object that this was defined in.

Using Object Methods

Object methods make using this much simpler. The value is always set to the object the method is called on, no matter how the method is defined.

What Is the Spread Syntax ?

Problem

You want a quick way of passing multiple arguments.

Solution

The spread syntax allows functions, arrays, or variables to accept multiple arguments.

The Code

function showSpread(one, two, three, four){
    console.log(one);
    console.log(two);
    console.log(three);
    console.log(four);
}
var myArray = [1,2,3,4];
//showSpread(myArray[0], myArray[1], myArray[2], myArray[3]) //without using spread
//showSpread(...myArray); //using the spread syntax
var dayInfo = [1975, 7, 19];
var dateObj = new Date(...dayInfo);
console.log(dateObj); //returns Tue Aug 19 1975 00:00:00 GMT-0400 (EDT)
var numArray2 = [ 2, 3, 4, 5, 6, 7]
var numArray = [1, ...numArray2, 8, 9, 10];
console.log(numArray); //returns 1, 2, 3, 4, 5, 6, 7, 8, 9, 10
var part1 = [1,2,3];
var part2 = [4,5,6];
var part3 = [...part1, ...part2];
console.log(part3); //returns 1,2,3,4,5,6
Listing 12-11.
Using the Spread Syntax

How It Works

The spread syntax can be used in multiple ways. The first example has a function that is expecting four different values. When the function is called, the spread syntax is being used to collect all the values at one time. The browser understands the syntax and splits the values into individual variables. This syntax can also be used in other function calls.
In a similar example, passing an array with date information over to the Date constructor can produce the correct date. The date contractor uses the spread syntax to take all the elements of the array and return a date object.
The next example shows how you can add elements to an array literal without using for loops. The spread syntax is used in the place of an element. This merges the two arrays. The result is a combined array with all of the elements present.
The spread syntax can be used with other functions like apply, and it can also be used more than once. The last example has two arrays. These two are merged into a third array using the spread syntax.
The ability to use the spread syntax more than once is available in any instance where you normally would use a spread.

What Are Rest Parameters?

Problem

You want a quick way of passing multiple arguments.

Solution

Similar to the spread syntax, the rest parameters allow for an indefinite amount of arguments to be passed to a function as an array.

The Code

function showSpread(one, two, three, four){
    console.log(one);
    console.log(two);
    console.log(three);
    console.log(four);
}
var myArray = [1,2,3,4];
//showSpread(myArray[0], myArray[1], myArray[2], myArray[3]) //without using spread
//showSpread(...myArray); //using the spread syntax
var dayInfo = [1975, 7, 19];
var dateObj = new Date(...dayInfo);
console.log(dateObj); //returns Tue Aug 19 1975 00:00:00 GMT-0400 (EDT)
var numArray2 = [ 2, 3, 4, 5, 6, 7]
var numArray = [1, ...numArray2, 8, 9, 10];
console.log(numArray); //returns 1, 2, 3, 4, 5, 6, 7, 8, 9, 10
var part1 = [1,2,3];
var part2 = [4,5,6];
var part3 = [...part1, ...part2];
console.log(part3); //returns 1,2,3,4,5,6
Listing 12-12.
Using the Spread Syntax

How It Works

Rest parameters are similar to using the spread syntax. Both start with three dots (...). One way of thinking about what makes them different is that a spread will take an object and “spread” the properties to work within a function. Rest will consolidate the properties into one array that can be used in the function.
Rest properties are also different from the arguments object. Both rest and arguments will allow you to access arguments that were passed to the function using an array-like syntax. The arguments object is not a true array, because of this, other methods that are part of the array object like map are not available.
The arguments object does have an object called callee. This method can refer to the function that is currently running inside another function. It is useful for referring to anonymous functions. However, it is not available when working in strict mode.
The first example shows how rest parameters can be added anywhere in an array. The first two properties are mapped with the last property using rest. When executed, the last property everyThingElse is an array containing all the values passed to the function. This can be tested by accessing the properties using the square brackets ([]).
The second example expands on the idea that the rest property is an array. Here we can use the forEach method. This method would not be available to the arguments object.

How Do Arrow Functions Work?

Problem

You want to create a function with a short syntax.

Solution

Arrow functions are shorter than the highly used function expressions. They are always anonymous and cannot be used as constructors.

The Code

//ES 5
document.getElementById('myButton').addEventListener('click', function(){
        var self = this;
        self.currentInterval = 0;
        setInterval(function myInterval(){
                self.currentInterval++;
        }, 1000);
});
//ES 6
document.getElementById('myButton').addEventListener('click', () => {
        this.currentInterval = 0;
        setInterval(() => {this.currentInterval++;}, 1000);
});
//retuning object literals
var myObj = () =>  ({name:'June'}) ;
console.log(myObj()); //returns Object {name: "June"}
Listing 12-13.
Using Arrow Functions

How It Works

Arrow functions give you a shorter way of creating functions. Using this syntax removes some of the features you would be used to having when using a function expression. Arrow functions are not named; they can be assigned to a variable but are always anonymous. The basic syntax has a set of parentheses that will hold all the parameters like a function expression. Next the arrow, then curly braces ({}) that will have the body of the function inside.
Parentheses are optional only when one parameter is being passed. If no parameters are being passed, parentheses are required.
Rest and default parameters are supported with arrow functions as well as with object destructuring.
When using arrow functions, keep in mind that the keyword this is not available. It inherits that property from the enclosing scope.
The first example first shows how the keyword this has different context between the callback function and the function associated with setInterval. The only way to bridge the gap is the create a new variable. The inner function (closure) can access the outer variable without using the keyword this.
The second example done with ES6 shows a similar version that is less verbose using the arrow functions. Because arrow functions inherit the property this (due to lexical scoping), you do not need to define another variable to reference the outer context.
If the arrow function needs to return an object literal, the object must be surrounded by parentheses. The reason for this is because if the block were to start with the curly braces ({}), the JavaScript engine does not know the difference between an object literal and the code block. Therefore, by surrounding the object with parentheses the object will be returned, even if the return keyword is not explicitly used.

What Are Parameter Defaults?

Problem

You want a default value for a parameter in case a value has not been passed.

Solution

Default parameters ensure that there is a value in case undefined or no value is passed.

The Code

function multiParams(one, two, three, four){
    if(typeof three == 'undefined'){
         console.log('three is undefined') //returns three is undefined
    }
    console.log(one); //returns 1
    console.log(two); //returns 2
    console.log(three);  //returns undefined
    console.log(four); // returns undefined
}
multiParams(1,2);
function playList(song = 'Seek 200'){
    console.log('Playing ' + song);
}
playList('Think'); //returns Playing Think
playList('Hack 1'); //returns Playing Hack 1
playList() //returns Playing Seek 200
Listing 12-14.
Using Argument Defaults

How It Works

In JavaScript when the function contains more parameters than what was passed to it, by default the remaining parameters have a value of undefined. In the past undefined can be checked by using the typeof operator.
Default parameters allow you to make sure a value is provided in any situation . If a value is passed, the function will accept that value; if not, then the default value takes over.
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.144.82.154