ES6 - Functions

Functions are the building blocks of readable, maintainable, and reusable code. Functions are defined using the function keyword. Following is the syntax for defining a standard function.
function function_name() { 
   // function body 
} 

To force execution of the function, it must be called. This is called as function invocation. Following is the syntax to invoke a function.
function_name()

//define a  function 
function test() { 
   console.log("function called") 
} 
//call the function 
test()
The example defines a function test(). A pair of delimiters ( { } ) define the function body. It is also called as the function scope. A function must be invoked to force its execution.
The following output is displayed on successful execution of the above code.
function called

Functions may be classified as Returning and Parameterized functions.
Functions may also return the value along with control, back to the caller. Such functions are called as returning functions.
Following is the syntax for the returning function.
function function_name() { 
   //statements 
   return value; 
}

A returning function must end with a return statement.
A returning function must end with a return statement.
A function can return at the most one value. In other words, there can be only one return statement per function.
A function can return at the most one value. In other words, there can be only one return statement per function.
The return statement should be the last statement in the function.
The return statement should be the last statement in the function.
The following code snippet is an example of a returning function −
function retStr() { 
   return "hello world!!!" 
}  
var val = retStr() 
console.log(val) 
The above Example defines a function that returns the string “hello world!!!” to the caller. The following output is displayed on successful execution of the above code.
hello world!!! 

Parameters are a mechanism to pass values to functions. Parameters form a part of the function’s signature. The parameter values are passed to the function during its invocation. Unless explicitly specified, the number of values passed to a function must match the number of parameters defined.
Following is the syntax defining a parameterized function.
function func_name( param1,param2 ,.....paramN) {   
   ...... 
   ...... 
}

Example − Parameterized Function
The Example defines a function add that accepts two parameters n1 and n2 and prints their sum. The parameter values are passed to the function when it is invoked.
function add( n1,n2) { 
   var sum = n1 + n2 
   console.log("The sum of the values entered "+sum) 
} 
add(12,13) 
The following output is displayed on successful execution of the above code.
The sum of the values entered 25

In ES6, a function allows the parameters to be initialized with default values, if no values are passed to it or it is undefined. The same is illustrated in the following code.
function add(a, b = 1) { 
   return a+b; 
} 
console.log(add(4))
The above function, sets the value of b to 1 by default. The function will always consider the parameter b to bear the value 1 unless a value has been explicitly passed. The following output is displayed on successful execution of the above code.
5

The parameter’s default value will be overwritten if the function passes a value explicitly.
function add(a, b = 1) { 
   return a + b; 
} 
console.log(add(4,2))
The above code sets the value of the parameter b explicitly to 2, thereby overwriting its default value. The following output is displayed on successful execution of the above code.
6

For better understanding, let us consider the below example.
The following example shows a function which takes two parameters and returns their sum. The second parameter has a default value of 10. This means, if no value is passed to the second parameter, its value will be 10.
<script>
   function addTwoNumbers(first,second = 10){
      console.log('first parameter is :',first)
      console.log('second parameter is :',second)
      return first+second;
   }

   console.log("case 1 sum:",addTwoNumbers(20)) // no value
   console.log("case 2 sum:",addTwoNumbers(2,3))
   console.log("case 3 sum:",addTwoNumbers())
   console.log("case 4 sum",addTwoNumbers(1,null))//null passed
   console.log("case 5 sum",addTwoNumbers(3,undefined))
</script>
The output of the above code will be as mentioned below −
first parameter is : 20
second parameter is : 10
case 1 sum: 30
first parameter is : 2
second parameter is : 3
case 2 sum: 5
first parameter is : undefined
second parameter is : 10
case 3 sum: NaN
first parameter is : 1
second parameter is : null
case 4 sum 1
first parameter is : 3
second parameter is : 10
case 5 sum 13

<script>
   let DEFAULT_VAL = 30
      function addTwoNumbers(first,second = DEFAULT_VAL){
         console.log('first parameter is :',first)
         console.log('second parameter is :',second)
         return first+second;
      }
      console.log("case 1 sum",addTwoNumbers(1))
      console.log("case 2 sum",addTwoNumbers(3,undefined))
</script>
The output of the above code will be as shown below −
first parameter is : 1
second parameter is : 30
case 1 sum 31
first parameter is : 3
second parameter is : 30
case 2 sum 33

Rest parameters are similar to variable arguments in Java. Rest parameters doesn’t restrict the number of values that you can pass to a function. However, the values passed must all be of the same type. In other words, rest parameters act as placeholders for multiple arguments of the same type.
To declare a rest parameter, the parameter name is prefixed with three periods, known as the spread operator. The following example illustrates the same.
function fun1(...params) { 
   console.log(params.length); 
}  
fun1();  
fun1(5); 
fun1(5, 6, 7); 
The following output is displayed on successful execution of the above code.
0 
1 
3

Note − Rest parameters should be the last in a function’s parameter list.
Functions that are not bound to an identifier (function name) are called as anonymous functions. These functions are dynamically declared at runtime. Anonymous functions can accept inputs and return outputs, just as standard functions do. An anonymous function is usually not accessible after its initial creation.
Variables can be assigned an anonymous function. Such an expression is called a function expression.
Following is the syntax for anonymous function.
var res = function( [arguments] ) { ... } 

Example − Anonymous Function
var f = function(){ return "hello"} 
console.log(f()) 
The following output is displayed on successful execution of the above code.
hello 

Example − Anonymous Parameterized Function
var func = function(x,y){ return x*y }; 
function product() { 
   var result; 
   result = func(10,20); 
   console.log("The product : "+result) 
} 
product()
The following output is displayed on successful execution of the above code.
The product : 200 

The function statement is not the only way to define a new function; you can define your function dynamically using Function() constructor along with the new operator.
Following is the syntax to create a function using Function() constructor along with the new operator.
var variablename = new Function(Arg1, Arg2..., "Function Body"); 

The Function() constructor expects any number of string arguments. The last argument is the body of the function – it can contain arbitrary JavaScript statements, separated from each other by semicolons.
The Function() constructor is not passed any argument that specifies a name for the function it creates.
Example − Function Constructor
var func = new Function("x", "y", "return x*y;"); 
function product() { 
   var result; 
   result = func(10,20); 
   console.log("The product : "+result)
} 
product()
In the above example, the Function() constructor is used to define an anonymous function. The function accepts two parameters and returns their product.
The following output is displayed on successful execution of the above code.
The product : 200

Recursion is a technique for iterating over an operation by having a function call itself repeatedly until it arrives at a result. Recursion is best applied when you need to call the same function repeatedly with different parameters from within a loop.
Example − Recursion
function factorial(num) { 
   if(num <= 0) { 
      return 1; 
   } else { 
      return (num * factorial(num-1)  ) 
   } 
} 
console.log(factorial(6)) 
In the above example the function calls itself. The following output is displayed on successful execution of the above code.
720 

Example − Anonymous Recursive Function
(function() { 
   var msg = "Hello World" 
   console.log(msg)
})()
The function calls itself using a pair of parentheses (). The following output is displayed on successful execution of the above code.
Hello World 

Lambda refers to anonymous functions in programming. Lambda functions are a concise mechanism to represent anonymous functions. These functions are also called as Arrow functions.
There are 3 parts to a Lambda function −
Parameters − A function may optionally have parameters.
Parameters − A function may optionally have parameters.
The fat arrow notation/lambda notation (=>): It is also called as the goes to operator.
The fat arrow notation/lambda notation (=>): It is also called as the goes to operator.
Statements − Represents the function’s instruction set.
Statements − Represents the function’s instruction set.
Tip − By convention, the use of a single letter parameter is encouraged for a compact and precise function declaration.
It is an anonymous function expression that points to a single line of code. Following is the syntax for the same.
([param1, parma2,...param n] )=>statement;

Example − Lambda Expression
var foo = (x)=>10+x 
console.log(foo(10)) 
The Example declares a lambda expression function. The function returns the sum of 10 and the argument passed.
The following output is displayed on successful execution of the above code.
20

It is an anonymous function declaration that points to a block of code. This syntax is used when the function body spans multiple lines. Following is the syntax of the same.
( [param1, parma2,...param n] )=> {       
   //code block 
}

Example − Lambda Statement
var msg = ()=> { 
   console.log("function invoked") 
} 
msg() 
The function’s reference is returned and stored in the variable msg. The following output is displayed on successful execution of the above code.
function  invoked 

Optional parentheses for a single parameter.
var msg = x=> { 
   console.log(x) 
} 
msg(10)
Optional braces for a single statement. Empty parentheses for no parameter.
var disp = ()=>console.log("Hello World") 
disp();

Function expression and function declaration are not synonymous. Unlike a function expression, a function declaration is bound by the function name.
The fundamental difference between the two is that, function declarations are parsed before their execution. On the other hand, function expressions are parsed only when the script engine encounters it during an execution.
When the JavaScript parser sees a function in the main code flow, it assumes function declaration. When a function comes as a part of a statement, it is a function expression.
Like variables, functions can also be hoisted. Unlike variables, function declarations when hoisted, hoists the function definition rather than just hoisting the function’s name.
The following code snippet, illustrates function hoisting in JavaScript.
hoist_function();  
function hoist_function() { 
   console.log("foo"); 
} 
The following output is displayed on successful execution of the above code.
foo 

However, function expressions cannot be hoisted. The following code snippet illustrates the same.
hoist_function(); // TypeError: hoist_function() is not a function  
var hoist_function() = function() { 
   console.log("bar"); 
};
Immediately Invoked Function Expressions (IIFEs) can be used to avoid variable hoisting from within blocks. It allows public access to methods while retaining privacy for variables defined within the function. This pattern is called as a self-executing anonymous function. The following two examples better explain this concept.
var main = function() { 
   var loop = function() { 
      for(var x = 0;x<5;x++) {
         console.log(x); 
      } 
   }(); 
   console.log("x can not be accessed outside the block scope x value is :"+x); 
} 
main();
var main = function() { 
   (function() { 
      for(var x = 0;x<5;x++) { 
         console.log(x); 
      } 
   })(); 
   console.log("x can not be accessed outside the block scope x value is :"+x); 
} 
main();
Both the Examples will render the following output.
0 
1 
2 
3 
4 
Uncaught ReferenceError: x is not define

When a normal function is invoked, the control rests with the function called until it returns. With generators in ES6, the caller function can now control the execution of a called function.  A generator is like a regular function except that −
The function can yield control back to the caller at any point.
The function can yield control back to the caller at any point.
When you call a generator, it doesn’t run right away. Instead, you get back an iterator. The function runs as you call the iterator’s next method.
When you call a generator, it doesn’t run right away. Instead, you get back an iterator. The function runs as you call the iterator’s next method.
Generators are denoted by suffixing the function keyword with an asterisk; otherwise, their syntax is identical to regular functions.
The following example illustrates the same.
"use strict" 
function* rainbow() { 
   // the asterisk marks this as a generator 
   yield 'red'; 
   yield 'orange'; 
   yield 'yellow'; 
   yield 'green'; 
   yield 'blue'; 
   yield 'indigo'; 
   yield 'violet'; 
} 
for(let color of rainbow()) { 
   console.log(color); 
} 
Generators enable two-way communication between the caller and the called function. This is accomplished by using the yield keyword.
Consider the following example −
function* ask() { 
   const name = yield "What is your name?"; 
   const sport = yield "What is your favorite sport?"; 
   return `${name}'s favorite sport is ${sport}`; 
}  
const it = ask(); 
console.log(it.next()); 
console.log(it.next('Ethan'));  
console.log(it.next('Cricket')); 
Sequence of the generator function is as follows −
Generator started in paused stated; iterator is returned.
Generator started in paused stated; iterator is returned.
The it.next() yields “What is your name”. The generator is paused. This is done by the yield keyword.
The it.next() yields “What is your name”. The generator is paused. This is done by the yield keyword.
The call it.next(“Ethan”) assigns the value Ethan to the variable name and yields “What is your favorite sport?” Again the generator is paused.
The call it.next(“Ethan”) assigns the value Ethan to the variable name and yields “What is your favorite sport?” Again the generator is paused.
The call it.next(“Cricket”) assigns the value Cricket to the variable sport and executes the subsequent return statement.
The call it.next(“Cricket”) assigns the value Cricket to the variable sport and executes the subsequent return statement.
Hence, the output of the above code will be −
{ 
   value: 'What is your name?', done: false 
} 
{ 
   value: 'What is your favorite sport?', done: false 
} 
{ 
   value: 'Ethan\'s favorite sport is Cricket', done: true 
}

Note − Generator functions cannot be represented using arrow functions.
Arrow functions which are introduced in ES helps in writing the functions in JavaScript in a concise manner. Let us now learn about the same in detail.
JavaScript makes heavy use of anonymous functions. An anonymous function is a function that does not have a name attached to it. Anonymous functions are used during function callback. The following example illustrates the use of an anonymous function in ES5 −
<script>
   setTimeout(function(){
      console.log('Learning at TutorialsPoint is fun!!')
   },1000)
</script>
The above example passes an anonymous function as a parameter to the predefined setTimeout() function. The setTimeout() function will callback the anonymous function after 1 second.
The following output is shown after 1 second −
Learning at TutorialsPoint is fun!!
ES6 introduces the concept of arrow function to simplify the usage of anonymous function. There are 3 parts to an arrow function which are as follows −
Parameters − An arrow function may optionally have parameters
Parameters − An arrow function may optionally have parameters
The fat arrow notation (=>) − It is also called as the goes to operator
The fat arrow notation (=>) − It is also called as the goes to operator
Statements − Represents the function’s instruction set
Statements − Represents the function’s instruction set
Tip − By convention, the use of a single letter parameter is encouraged for a compact and precise arrow function declaration.
//Arrow function that points to a single line of code
()=>some_expression

//Arrow function that points to a block of code
()=> { //some statements }`

//Arrow function with parameters
(param1,param2)=>{//some statement}

The following example defines two function expressions add and isEven using arrow function
<script>
   const add = (n1,n2) => n1+n2
   console.log(add(10,20))

   const isEven = (n1) => {
      if(n1%2 == 0)
         return true;
      else
         return false;
   }
   console.log(isEven(10))
</script>
The output of the above code will be as mentioned below −
30
true

In the following example, an arrow function is passed as a parameter to the Array.prototype.map() function. The map() function executes the arrow function for each element in the array. The arrow function in this case, displays each element in the array and its index.
<script>
   const names = ['TutorialsPoint','Mohtashim','Bhargavi','Raja']
   names.map((element,index)=> {
      console.log('inside arrow function')
      console.log('index is '+index+' element value is :'+element)
   })
</script>
The output of the above code will be as given below −
inside arrow function
index is 0 element value is :TutorialsPoint
inside arrow function
index is 1 element value is :Mohtashim
inside arrow function
index is 2 element value is :Bhargavi
inside arrow function
index is 3 element value is :Raja

The following example passes an arrow function as a parameter to the predefined setTimeout() function. The setTimeout() function will callback the arrow function after 1 second.
<script>
   setTimeout(()=>{
      console.log('Learning at TutorialsPoint is fun!!')
   },1000)
</script>
The following output is shown after 1 second −
Learning at TutorialsPoint is fun!!

Inside an arrow function if we use this pointer, it will point to the enclosing lexical scope. This means arrow functions do not create a new this pointer instance whenever it is invoked. Arrow functions makes use of its enclosing scope. To understand this, let us see an example.
<script>
   //constructor function
   function Student(rollno,firstName,lastName) {
      this.rollno = rollno;
      this.firstName = firstName;
      this.lastName = lastName;
      this.fullNameUsingAnonymous = function(){
         setTimeout(function(){
            //creates a new instance of this ,hides outer scope of this
            console.log(this.firstName+ " "+this.lastName)
         },2000)
      }
      this.fullNameUsingArrow = function(){
         setTimeout(()=>{
            //uses this instance of outer scope
            console.log(this.firstName+ " "+this.lastName)
         },3000)
      }
   }
   const s1 = new Student(101,'Mohammad','Mohtashim')
   s1.fullNameUsingAnonymous();
   s1.fullNameUsingArrow();
</script>
When an anonymous function is used with setTimeout(), the function gets invoked after 2000 milliseconds. A new instance of “this” is created and it shadows the instance of the Student function. So, the value of this.firstName and this.lastName will be undefined. The function doesn't use the lexical scope or the context of current execution. This problem can be solved by using an arrow function.
The output of the above code will be as follows −