whenever life put's you in a tough situtation, never say why me! but, try me!

Certainly! Let’s expand Chapter 3 to include higher-order functions and recursive functions.


Chapter 3: Functions

Function Declaration

A function declaration defines a function with a name and a block of code. It is the most common way to define functions and can be called before its declaration due to JavaScript's function hoisting.

Syntax:

function functionName(parameters) {
  // code to execute
}

Example:

function greet(name) {
  console.log("Hello, " + name + "!");
}

greet("Alice"); // Output: Hello, Alice!

Function Expression

A function expression defines a function as part of an expression and does not have a name. It is assigned to a variable and can only be called after the expression is defined.

Syntax:

const functionName = function (parameters) {
  // code to execute
};

Example:

const greet = function (name) {
  console.log("Hello, " + name + "!");
};

greet("Bob"); // Output: Hello, Bob!

Arrow Functions

Arrow functions provide a shorter syntax for writing function expressions. They are especially useful for writing concise functions, and they inherit the this context from their surrounding scope.

Syntax:

const functionName = (parameters) => {
  // code to execute
};

For single-line functions that return a value, you can omit the curly braces and the return keyword:

Example:

const greet = (name) => console.log("Hello, " + name + "!");

greet("Charlie"); // Output: Hello, Charlie!

Example with Multiple Parameters:

const add = (a, b) => a + b;

console.log(add(5, 3)); // Output: 8

Parameters and Arguments

Parameters are the names listed in the function definition. Arguments are the actual values passed to the function when it is called.

Example:

function multiply(x, y) {
  return x * y;
}

let result = multiply(4, 5); // Arguments: 4 and 5
console.log(result); // Output: 20
  • x and y are parameters.
  • 4 and 5 are arguments.

Default Parameters

You can provide default values for parameters in case no arguments are passed or undefined is provided.

Example:

function greet(name = "Guest") {
  console.log("Hello, " + name + "!");
}

greet(); // Output: Hello, Guest!
greet("Dave"); // Output: Hello, Dave!

Return Values

Functions can return values using the return statement. If no return statement is used, the function returns undefined.

Syntax:

function functionName(parameters) {
  return value;
}

Example:

function square(number) {
  return number * number;
}

let result = square(7);
console.log(result); // Output: 49

Scope and Closures

Scope

Scope refers to the visibility and lifetime of variables. There are two types of scope:

  1. Global Scope: Variables declared outside any function or block are globally scoped and can be accessed anywhere in the code.

  2. Local Scope: Variables declared inside a function or block are locally scoped and can only be accessed within that function or block.

Example:

let globalVariable = "I am global";

function showVariable() {
  let localVariable = "I am local";
  console.log(globalVariable); // Accessible
  console.log(localVariable); // Accessible
}

showVariable();
console.log(globalVariable); // Accessible
console.log(localVariable); // Error: localVariable is not defined

Closures

A closure is a feature where a function retains access to its lexical scope (the scope in which it was created) even after the function has returned. This allows functions to access variables from their outer scope.

Example:

function makeCounter() {
  let count = 0;

  return function () {
    count++;
    return count;
  };
}

const counter = makeCounter();

console.log(counter()); // Output: 1
console.log(counter()); // Output: 2
console.log(counter()); // Output: 3

In this example, the inner function retains access to the count variable from the makeCounter function’s scope, even after makeCounter has finished executing.

Higher-Order Functions

A higher-order function is a function that takes another function as an argument, returns a function, or both. Higher-order functions are useful for creating more abstract and reusable code.

Example of a Higher-Order Function that Takes a Function as an Argument:

function operateOnNumbers(a, b, operation) {
  return operation(a, b);
}

function add(x, y) {
  return x + y;
}

console.log(operateOnNumbers(5, 3, add)); // Output: 8

In this example, operateOnNumbers is a higher-order function because it takes another function (add) as an argument and applies it.

Example of a Higher-Order Function that Returns a Function:

function createMultiplier(multiplier) {
  return function (value) {
    return value * multiplier;
  };
}

const double = createMultiplier(2);
console.log(double(5)); // Output: 10

const triple = createMultiplier(3);
console.log(triple(5)); // Output: 15

Here, createMultiplier is a higher-order function that returns another function. The returned function uses the multiplier value provided when createMultiplier was called.

Recursive Functions

A recursive function is a function that calls itself in order to solve a problem. Recursive functions are particularly useful for tasks that can be broken down into simpler, similar tasks.

Syntax:

function recursiveFunction(parameters) {
  if (baseCase) {
    // base case to end recursion
  } else {
    // recursive call
    recursiveFunction(modifiedParameters);
  }
}

Example of a Recursive Function:

function factorial(n) {
  if (n === 0) {
    return 1; // base case
  } else {
    return n * factorial(n - 1); // recursive call
  }
}

console.log(factorial(5)); // Output: 120

In this example, factorial calculates the factorial of a number using recursion. The base case is when n is 0, where the function returns 1. For other values, the function calls itself with n - 1.