loading...
Cover image for Why nested functions in JavaScript

Why nested functions in JavaScript

rajajaganathan profile image Raja Jaganathan ・3 min read

Often many people confused about nested function in JavaScript, why the nested function is useful, and what is the use case for nested function? There are so many places we might encounter such nested functions in our code or blog post or articles.

In this article, I would like to talk about the basics of why nested functions are useful in many ways.

I'll start asking some basic questions along with some constraints that way it may help to think differently to solve the problem. Let's assume that we have employee array like below

const employee = [
  { id: 1, name: "Raja", age: 28, status: "active" },
  { id: 2, name: "Andy", age: 32, status: "Inactive" },
  { id: 3, name: "Kumar", age: 45, status: "active" },
  { id: 4, name: "Charles", age: 35, status: "Inactive" },
];

Use case 1 #

How do you sort an array by property (age, status, etc)?

Constraint: Do not pass an array as a reference to any other functions and function should be more reusable.

Typically, with our prior programming knowledge, we do sorting using Array.prototype.sort function like below

function sortBy(array, propName) {
  return array.sort(function (a, b) {
    if (a[propName] > b[propName]) {
      return 1;
    } else if (a[propName] < b[propName]) {
      return -1;
    } else {
      return 0;
    }
  });
}

console.log(sortBy(employee, "age"));
console.log(sortBy(employee, "status"));

The above code does the job nicely but just take a look into our first constraint for the first use case. so it's clearly saying that's not the way to do. Note that, we are passing array reference to the function :(

In general, this is how we do sorting in JavaScript

// How do to pass another arguments to tell sort based on which property of an object ???????
Array.prototype.sort(function(a, b)) 

As we know Array.prototype.sort interface only accepts 2 arguments, So How do we pass propName as another argument? now we clearly understand that sort method accepts only 2 parameters we can't pass any extra argument to the function anymore.

Okay then how do we solve the problem?.

Hint: can we make our custom argument accessible inside sort callback function without adding an extra argument to Array.prototype.sort?

Alt Text

This is a perfect moment to use function inside a function (often called higher-order function) so that we could return a function which accepts only 2 arguments as per sort interface requirement, the high order function can accept n of arguments so that we can access our custom argument inside the sort callback function.

Here is the second version of sortBy function


function sortBy(propName) {
  return function (a, b) { // obeying sort interface function signature
    if (a[propName] > b[propName]) { // propName accessible from highorder function
      return 1;
    } else if (a[propName] < b[propName]) {
      return -1;
    } else {
      return 0;
    }
  };
}

console.log(employee.sort(sortBy("age")));
console.log(employee.sort(sortBy("status")));

I would like to discuss one more use case for higher-order functions with filter use case

Use case 2:

How do you filter an array with an inactive employee?

Constraint: Assume that we have function for filter out all active employee(isActiveEmployee) function already exists, Use the same function to get all inactive employee without code duplication.

function isActiveEmployee(employee) {
    return employee.status == 'active';
}

const activeEmployee = employee.filter(isActiveEmployee);
// const inactiveEmployee = employee.filter(??????);

Okay we might come up with below solution easy without thinking anything

function isInactiveEmployee(employee) {
     return employee.status !== 'active';
}

//(or)

 function isInactiveEmployee(employee) {
     return employee.status === 'inactive';
}

Just gentle reminder of use case 2's constraint, it said, we should n't duplicate the code, so can we do it a better way?

So think of we have already code which finds all active employees, so it just to invert the result of isActiveEmployee function we will get the all inactive employee even without write a brand new function for filter out inactive employee.

Method looks like

 function negate(item){
     return !isActiveEmployee(item)
 }

But we can do even better, we may think of negate as utility functions so it can be written like below

  function negate(predicate){
      return function() {
          return !predicate.apply(this, arguments)
      }
  }

Here is solution for filtered out all inactive employee

const inactiveEmployee = employee.filter(negate(isActiveEmployee));

console.log({inactiveEmployee});

Hope now you can see some of the benefits of high order function such as

  1. Cleaner abstraction
  2. working with composable functions and many more

Further Readings:

https://eloquentjavascript.net/05_higher_order.html
https://javascript.info/currying-partials

Posted on May 25 by:

rajajaganathan profile

Raja Jaganathan

@rajajaganathan

JavaScript/TypeScript, React, Node developer

Discussion

markdown guide
 

Such an important principle - nice article!

 

Awesome, love ways to shorten my code! Thank you for this!

 

Great article Raja, thank you so much! It helps me a lot!!!

 

I'm so glad that it helps!

 

This gives clear picture and usage of nested functions. it helps me to make the cleaner code.