JavaScript Functions

JavaScript functions are capable of more than just merely enclosing a bunch of codes while waiting for the call to execute. Functions have evolved over time leading to new definitions, execution methods and syntaxes. This post will cover some of the present roles JavaScript functions have played so far.

Knowing the different ways of expressing and defining functions opens up the possibility of implementing a logic in a more optimal way in JavaScript. Also, you may be able to answer the interview questions more easily.

Function Expressions

When you simply state a function with function keyword , optional parameters and body of code, it’s a function declaration.

Put that declaration in a JavaScript expression (like in an assignment or arithmetic expression), it becomes a function expression.

// Function declaration
function function_name() {};
// Function expression
var function_name = function() {};

All JavaScript declarations are hoisted (moved up in the scope) during evaluation. Hence writing a function call before the function declaration is okay (since the declaration will be moved up anyway).

function_name();//function call[WORKS]
function function_name(){};

Function expressions however aren’t hoisted since the functions become part of the expressions and are not stand-alone declarations.

function_name();//function call[WON'T WORK]
var function_name = function(){};

Immediately Invoked Function Expression (IIFE)

It’s a function expression, the code of which gets executed immediately (only once when it’s evaluated). You can create one by simply adding () (syntax used for calling a function) right after a function expression. They can be anonymous (no name to call it with).

Below are the two most common syntaxes to create IIFE:

(function optional_function_name() {
  //body
}());

and

(function optional_function_name() {
  //body
})();

The parenthesis around the function declaration converts it to an expression and then adding () after it calls the function. You can use other ways to create IIFE for as long as you add () after a function expression (like below), but the preferred methods are the above two.

// Some of the ways to create IIFEs
!function() { /* ... */ }();
+function() { /* ... */ }();
new function() { /* ... */ };

IIFE is ideal for writing code that needs to execute only once, namespacing, creating closures, creating private variables and more. Below is an example of IIFE use.

var page_language = (function () {
  var lang;
  // Code to get the language of the page
  return lang;
})();

The code to get the page’s language executes only once (preferably after the page loads). The result is stored in page_language for later use.

Methods

When a function is an object’s property, it is called method. Since a function is also an object, a function inside another function is also a method. Below is an example for a method inside object.

var calc = {
  add : function(a,b){return a+b},
  sub : function(a,b){return a-b}  
}
console.log(calc.add(1,2)); //3
console.log(calc.sub(80,2)); //78

The add and sub functions are methods of calc object.

Now for a function within function example:

function add(a){
  return function(b){return a+b;}
}
console.log(add(1)(2)); // Output is 3

The returned anonymous function is a method of function add.

Note: Since parameter (a) of function add in the above example is available for the following function invoke, this type of process is called currying.

Constructors

When you add new keyword before a function and call it, it becomes a constructor that creates instances. Below is an example where constructors are used to create instances of Fruit and values are added to each Fruit‘s properties.

function Fruit(){   
  var name, family; // Scientific name & family
  this.getName = function(){return name;};
  this.setName = function(value){name=value};   
  this.getFamily = function(){return family;};
  this.setFamily = function(value){family=value}; 
}

var apple = new Fruit();
apple.setName("Malus domestica");
apple.setFamily("Rosaceae");

var orange = new Fruit();
orange.setName ("Citrus × sinensis");
orange.setFamily ("Rutaceae");

console.log(orange.getName()); // "Citrus × sinensis"
console.log(apple.getName()); // "Malus domestica"
console.log(orange.getFamily()); // "Rutaceae"

Arrow Functions (ES6 Standard) [Only in Firefox]

A new function definition from ES6 Standard provides a shorter syntax for function expression. The syntax is

() => { /* body */ }

This sample function:

var sing = function(){
  console.log('singing...')
};

is the same as:

var sing = () => {
  console.log('singing...')
};

Arrow functions are anonymous and does not have its own this value, this inside it will be same as this in the enclosing code. Also, you cannot change it to a constructor with new keyword.

They are useful for when you want this inside a function to be the same as outside and its shorter syntax makes code for writing function within function concise (like below)

setInterval(function () {
  console.log('message')
}, 1000);

into

setInterval(() => console.log('message'), 1000);

Generator Functions (ES6 Standard) [Only in Firefox]

Another new function definition from ES6 Standard is Generator Function. Generator functions are capable of halting and continuing its execution. Its syntax is:

function* function_name(){}

or

function *function_name(){}

Generator functions create iterators. The iterator’s next method is then used to execute the code inside the generator function until the yield keyword is reached. After that, the iterated value identified by the yield keyword is returned by the generator function and the execution is halted.

The generator function again executes when the next method is called until the next yield keyword is reached. Once all of the yield expressions are executed, the yielded value returns undefined.

Below is a simple example:

function *generator_func(count) {
  for(var i=0;i<count;i++){
    yield i+1;
  }
}

var itr = generator_func(4); 
console.log(itr.next()); //Object { value: 1, done: false }
console.log(itr.next()); //Object { value: 2, done: false }
console.log(itr.next()); //Object { value: 3, done: false }
console.log(itr.next()); //Object { value: 4, done: false }
console.log(itr.next()); //Object { value: undefined, done: true }
console.log(itr.next()); //Object { value: undefined, done: true }

Here’s another example:

function *randomIncrement(i) {
 yield i + 3;
 yield i + 5;
 yield i + 10;
 yield i + 6;
}
var itr = randomIncrement(4);
console.log(itr.next().value); //7
console.log(itr.next().value); //9
console.log(itr.next().value); //14

There’s also a yield* expression which passes the value to another generator function

function *fruits(fruit) {
 yield* veggies(fruit); 
 yield "Grapes";
}

function *veggies(fruit){
 yield fruit + " and Spinach";
 yield fruit + " and Broccoli";
 yield fruit + " and Cucumber";
}

var itr = fruits("Apple");
console.log(itr.next().value); //"Apple and Spinach"
console.log(itr.next().value); //"Apple and Broccoli"
console.log(itr.next().value); //"Apple and Cucumber"
console.log(itr.next().value); //"Grapes"
console.log(itr.next().value); //undefined

Generator functions are useful if you want to go through values one by one at your preferred point in the code by pausing it, rather than in one go like in looping through an array.

Conclusion

I’ve included a list of references below, where you will find links to references and articles that go in-depth on different topics separately. Both the ES6 standard functions will work only in Firefox at the moment.

References

FacebookTwitterInstagramPinterestLinkedInGoogle+YoutubeRedditDribbbleBehanceGithubCodePenEmail