Mastering JavaScript Functions: Understanding the Different Types


What is Function?

In JavaScript, a function is a block of code that can be executed by calling it by its name, and can optionally take in parameters and return a value. Functions are a fundamental building block in JavaScript and are used to perform specific tasks or compute values. They are often used to organize and structure code, making it more modular and reusable. Functions can be declared in several ways in JavaScript, including function declarations, function expressions, and arrow functions.

Function Declaration

A function declaration in JavaScript is a way to define a function and make it available for use in your code. It follows a specific syntax, where the keyword "function" is followed by the function name, a set of parentheses that may include parameters, and a block of code enclosed in curly braces that defines the function's behavior.

For example

function add(a, b) {
    return a + b;
}

In this example, the function is named "add" and it takes in two parameters, "a" and "b". The function's behavior is defined within the curly braces, where it simply returns the sum of "a" and "b". This function can now be called by referencing its name, followed by the arguments in parentheses, like so:

let result = add(3, 5);  // result = 8

Function declarations are hoisted, which means that they are available for use throughout the entire scope in which they are defined, even before they are executed. This allows you to call a function before it is defined in your code.

Function with a return statement

A function with a return statement is a function that, when called, evaluates one or more expressions and returns a value to the calling code. The return statement is used to specify the value that the function should return.

For example

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

In this example, the function add takes two parameters a and b, and returns their sum using the return statement. When the function is called with the arguments 1 and 2, it returns the value 3 which is then logged to the console. Function with return statement can be used to perform calculation, make decision and return the output as per the requirement.

Function with Arbitrary arguments

In JavaScript, a function can accept an arbitrary number of arguments using the "arguments" keyword. This keyword refers to an object that contains all of the arguments passed to the function. The arguments can be accessed like an array, using square brackets []. For example:

function sum() {
    let total = 0;
    for (let i = 0; i<arguments.length; i++) {
        total += arguments[i];
    }
    return total;
}

console.log(sum(1, 2, 3)); // 6
console.log(sum(1, 2, 3, 4, 5)); // 15

Additionally, the spread operator (...) can also be used to accept an arbitrary number of arguments. The spread operator allows the elements of an array to be spread out into individual arguments. For example:

function sum(...args) {
    let total = 0;
    for (let i = 0; i<args.length; i++) {
        total += args[i];
    }
    return total;
}

console.log(sum(1, 2, 3)); // 6
console.log(sum(1, 2, 3, 4, 5)); // 15

Both the examples will give the same output.

Function as Expression

In JavaScript, a function can also be defined as an expression. This means that a function can be assigned to a variable or passed as an argument to another function.

For example, the following code defines a function and assigns it to a variable named "add":

const add = function(a, b) {
    return a + b;
};
console.log(add(1, 2)); // 3

Arrow Function

An arrow function, also known as a "fat arrow" function, is a shorthand syntax for defining a function in JavaScript. It was introduced in ECMAScript 6 (ES6) and is now a widely used feature in JavaScript development.

The basic syntax for an arrow function is as follows:

const functionName = (parameters) =>{ function body };
For example

const add = (a, b) =>{ return a + b };
console.log(add(1, 2)); // 3

If the function body contains a single expression, you can also use the shorthand syntax, omitting the curly braces and the "return" keyword:

const add = (a, b) => a + b;
console.log(add(1, 2)); // 3

Arrow functions have some important differences when compared to traditional function expressions:

  • The "this" keyword inside an arrow function refers to the same "this" as the surrounding scope, and it is not redefined when the function is invoked.
  • Arrow functions do not have a "arguments" object, and you should use the rest parameter syntax instead.
  • Arrow functions cannot be used as constructors.
  • Arrow functions are useful for creating concise, readable code and for passing anonymous functions as arguments to other functions.

Here is the some more examples of using arrow functions in JavaScript with detailed explanations:

1. Using arrow functions with map():

let numbers = [1, 2, 3, 4, 5];
let doubledNumbers = numbers.map(number => number * 2);
console.log(doubledNumbers); // [2, 4, 6, 8, 10]

In this example, the map() method is used to iterate over an array of numbers and double each one. The arrow function number => number * 2 is passed as an argument to the map() method and is invoked for each element in the array. The result is a new array with the doubled numbers.

2. Using arrow functions with filter():

let words = ['apple', 'banana', 'orange', 'grape'];
let filteredWords = words.filter(word =>word.length> 5);
console.log(filteredWords); // ['banana', 'orange']

In this example, the filter() method is used to filter out elements in an array of words that are shorter than 5 characters. The arrow function word =>word.length> 5 is passed as an argument to the filter() method and is invoked for each element in the array. The result is a new array containing only the words that are longer than 5 characters.

3. Using arrow functions with reduce():

let numbers = [1, 2, 3, 4, 5];
let total = numbers.reduce((sum, number) => sum + number, 0);
console.log(total); // 15

In this example, the reduce() method is used to iterate over an array of numbers and add them together. The arrow function (sum, number) => sum + number is passed as the first argument to the reduce() method and is invoked for each element in the array. The second argument, 0, is the initial value of the accumulator (sum). The result is the total sum of all the numbers in the array.

4. Using arrow functions to create a closure:

let createCounter = () => {
  let count = 0;
  return () => {
    count++;
    return count;
  };
};
let counter = createCounter();
console.log(counter()); // 1
console.log(counter()); // 2

In this example, the reduce() method is used to iterate over an array of numbers and add them together. The arrow function (sum, number) => sum + number is passed as the first argument to the reduce() method and is invoked for each element in the array. The second argument, 0, is the initial value of the accumulator (sum). The result is the total sum of all the numbers in the array.

In this example, an arrow function is used to create a closure. The outer function createCounter returns an inner function that increments and returns a variable count. Because the inner function is defined inside the outer function, it has access to the variable count and maintains its state even after the outer function has returned.

These examples demonstrate how arrow functions can be used to write more concise and readable code, particularly when working with arrays, functions, and closures.

Default Parameter Function

A default parameter function is a function in which one or more parameters have a default value specified. In the event that the caller of the function does not provide a value for that parameter, the default value will be used instead.

function addition(a,b=5)
{
    return a+b;
}
console.log(addition(25,30));
console.log(addition(25));

In the above code, the function "addition" has two parameters: "a" and "b". The parameter "b" has a default value of 5, meaning that if the caller of the function does not provide a value for "b", the value 5 will be used.

The first call to the function, "console.log(addition(25,30))", passes in two arguments: 25 for "a" and 30 for "b". The function returns the sum of these values (25 + 30 = 55), which is then logged to the console.

The second call to the function, "console.log(addition(25))", only passes in one argument: 25 for "a". Since no value is provided for "b", the default value of 5 is used. The function returns the sum of these values (25 + 5 = 30), which is then logged to the console.

Function hoisting

Function hoisting is a feature in JavaScript that allows you to call a function before it is defined in the code. This occurs because when JavaScript is interpreted, all function declarations are moved to the top of their scope, which is known as hoisting.

Here's an example of function hoisting:

hoistedFunction(); // Output: "I'm a hoisted function"

function hoistedFunction() {
   console.log("I'm a hoisted function");
}

In this example, the function hoistedFunction is called before it is defined in the code. However, it still executes successfully because the function declaration is hoisted to the top of the scope, making it available to call throughout the entire scope.

It's important to note that function hoisting applies only to function declarations and not function expressions.

notHoistedFunction(); // ReferenceError
let notHoistedFunction = function(){
    console.log("I'm a function expression");
}

In this example, calling notHoistedFunction before the function expression is defined will result in a ReferenceError

Function hoisting can be useful in certain situations but it can also lead to unexpected behavior if not used correctly. It's good practice to always define functions before calling them in your code to avoid confusion and bugs.

Nested Function

In JavaScript, it is possible to define a function inside another function, also known as a nested function. A nested function has access to the variables and functions in the parent function's scope, also known as the enclosing scope.

Here's an example of a nested function:

function outerFunction() {
  let outerVariable = 'I am a variable in the outer function';

  function innerFunction() {
    let innerVariable = 'I am a variable in the inner function';
    console.log(outerVariable); // Output: "I am a variable in the outer function"
    console.log(innerVariable); // Output: "I am a variable in the inner function"
  }

innerFunction();
}
outerFunction();

In this example, the outerFunction defines a variable called outerVariable and a nested function called innerFunction. The innerFunction has access to the outerVariable and can access and use it.

Nested functions can be useful for creating more modular and organized code. They can also be used to create closures, which are functions that maintain their state even after they have returned.

It's important to note that inner functions have access to the variables and functions in the parent function, but the parent function doesn't have access to the variables and functions inside the inner function.

Also, the inner function can be invoked only by the parent function.

Lexical scope in JavaScript function

In JavaScript, lexical scope refers to the way in which the variables, functions, and objects in a program are associated with specific scopes, or regions of the code where they are accessible. Each function in JavaScript has its own scope, which is determined by the location of the function in the code, and the scopes of any parent functions that contain it.

Here's an example of lexical scope in JavaScript:

let globalVariable = 'I am a global variable';

    function outerFunction() {
      let outerVariable = 'I am a variable in the outer function';

      function innerFunction() {
        let innerVariable = 'I am a variable in the inner function';
        console.log(globalVariable); // Output: "I am a global variable"
        console.log(outerVariable); // Output: "I am a variable in the outer function"
        console.log(innerVariable); // Output: "I am a variable in the inner function"
      }

    innerFunction();
    }
    outerFunction();

In this example, the innerFunction has access to variables in the outerFunction scope and global scope. However, the outerFunction doesn't have access to the variables in the innerFunction scope.

JavaScript uses a scope chain to determine which variables are accessible in a particular scope. The scope chain starts with the local scope and then moves up to the parent scope, and so on, until it reaches the global scope.

JavaScript has a lexical scoping which means that the scope of a variable is defined by its location in the code, and not by its execution context.Understanding lexical scope is an important part of understanding how JavaScript works and can help you write more efficient and effective code.

List of Programs


JS Practical Questions & Answers


JS Practical Project