Function is a block of code designed to perform a particular task, executed when called or invoked

Declarations


  • Function

function functionName(param) {
// code to be executed
}
  • Function Expression

    • Not hoisted
const functionName = function (param) {
// code to be executed
}
  • Arrow Function

    • Un-named function, also called as lambda functions
const functionName = (param) => {
// code to be executed
}

Types


1. Anonymous function

  • Functions without a name, often used as arguments or assigned to variables.

2. Named functions

  • With a specific name.

3. Immediately invoked functions ( IIFE )

  • Immediately executed after defined.

Scope


  • Scope of function is the function in which it is declared or the whole program if defined in top level

Hoisting


Function declarations and generator functions are value hoisted. Function expressions are not hoisted. Refer - Hoisting

Closures


  • A function that retains access to its outer scope variables. Before ES6, this was the way to emulate private variables.
  • Lexical Environment is created when a function is declared, so closures only form when a function is declared inside a function.

Callbacks


  • A function which is passed an argument to another function. Now the parent function can call this function after some tasks
function parent(cb) {
	setTimeout(()=>{
		console.log("Time elapsed");
		cb("Called callback");
	}, 100);
}
 
function callbackDemoFunction(message) {
	console.log(message);
}

Higher-Order Functions


  • Function that takes one or more arguments as a function or returns a function.

Default Parameter in a function


function greet(name = 'Guest') {
  console.log(`Hello, ${name}`);
}
greet(); // Hello, Guest
greet('Alice'); // Hello, Alice

Spread operator


  • Allows iterable to be expanded in places where 0 or more arguments or elements are expected
const numbers = [1, 2, 3];
console.log(Math.max(...numbers)); // 3
 
function sum(a, b, c) {
  return a + b + c;
}
console.log(sum(...numbers)); // 6
 

Rest Parameter


  • The rest parameter is a syntax that allows a function to take indefinite parameters in a array. This was introduced in ES6.
function sum(...theArgs) {
  let total = 0;
  for (const arg of theArgs) {
    total += arg;
  }
  return total;
}
 
console.log(sum(1, 2, 3));
// Expected output: 6
  • In ES5, arguments variable used to be present, which consists of all the parameters passed, but this was not a true array and forEach, map array methods were not present.

Function binding


  • Here greet is a method of person, which refers to name in the object context.
const person = {
	name : "Adesh",
	greet: function() {
		console.log("Hello ", this.name);
	}
}
 
// Calling greet method with the object
person.greet() // Outputs -> Hello Adesh
  • Assigning the greet method to a variable, this makes it loose its context.
const greetFunc = person.greet;
 
greetFunc() // Outputs -> undefined
  • bind returns a function with a context for this attached to it.
const greetFunc = person.greet.bind(person);
 
// OR
 
const greeFunc = person.greet.bind({name: "SomeoneElse"});
  • An interesting approach - It works as this refers to the object which owns the method rather then who or where its defined.
const person = {
	greet: function (){
		console.log("Hello ",this.name)
	}
}
 
let anotherPerson = {
	name : "SomeoneElse"
}
 
anotherPerson.greet = person.greet;
 
anotherPerson.greet() // Outputs -> Hello SomeoneElse

Asynchronous functions


  • Async/Await: Simplifies working with asynchronous code by allowing you to write asynchronous functions using the async and await keywords.
async function fetchData() {
  let response = await fetch('https://api.example.com/data');
  let data = await response.json();
  console.log(data);
}
 
fetchData();

Generator Functions


  • The function defined as function* syntax
  • Generator functions are special type of functions that makes easy to implement the iterators. When a generator function is called, it returns a generator which can be called only once and it will execute the code till the yield keyword in the function and return the yield value.
function* makeRangeIterator() {
 
    let iterationCount = 20;
    for (let i = 0; i < 4; i += 1) {
        iterationCount++;
        yield i;
    }
    return iterationCount
}
 
const iter = makeRangeIterator();
 
for(let val of iter) {
    console.log(val);
}
  • The for...of loop exhaust the yields and does not capture the return statement. The return statement is executed or returned after all the yields are exhausted. Below is the example of how to capture the return.
let result;
 
while( !result?.done) {
    result = iter.next();
    console.log(result);
}

Functions properties and methods


  • name returns the name of the functions
  • length returns the length of the arguments expected in the function
  • call and apply methods call the function by providing the values for this
function greet(param) {
    console.log(this);
    console.log(param);
}
 
const person1 = { name: "Dave" };
greet.call(person1, "John"); // Output -> { name: "Dave" } John
 
greet.apply(person1, ["John"]); // Output -> { name: "Dave" } John