Anonymous Or Named?

Open the project folder

In our starter files, open the index.html page from this lessons folder:

03.Functions > 04.Anonymous-or-named

Using function names

When we have looked at function expressions, we have left out the name and therefore referred to these functions as anonymous. But is no name the best way to approach creating functions? It is certainly shorter, and we can still call the functions, so why use them?

In the starter files, we have a named and anonymous function example:

let bread = ['flour', 'yeast', 'salt', 'water'];
let brownies = ['butter', 'chocolate', 'flour', 'eggs', 'sugar'];

// named function
function numberOfIngredients(recipe) {
  return recipe.length;
}

// anonymous
const checkAllergies = function (recipe, ingredient) {
  const hasIngredient = recipe.includes(ingredient);
  return hasIngredient;
};

Ignore the example below this for now. The first example shows a regular, named function, and then an anonymous function since we have not directly gave the function a name after the function keyword.

The name property

Functions have a read-only property called name, over to the console where we can look at this. Type numberOfIngredients.name into the console:

> numberOfIngredients.name
< "numberOfIngredients"

And unsurprisingly, since this is a named function, we get back the function name.

But what about checkAllergies? Remember this is an anonymous function since we have no name after the function keyword. Let’s try calling it by the variable name:

> checkAllergies.name
>"checkAllergies"

Inferred function names

For this we still get back a name. And this is because of something called an inferred function name. Since the function is stored in a variable, JavaScript has guessed that this name can be used for our function.

As we are starting to understand, functions and the way we can refer to them take on many forms, and this inferred name is not always reliable in some situations. There are certain times or edge cases when the name is not inferred.

But one of the reasons you may want a specific name to the function is for debugging errors in the console. To see this, create a typing error in the anonymous function:

const checkAllergies = function (recipe, ingredient) {
// 1. typo
const hasIngredient = recipe.ncludes(ingredient);
return hasIngredient;
};

// 2. log to console
console.log(checkAllergies(bread, 'salt'));

The Chrome developer tools has detected an error:

Uncaught TypeError: recipe.ncludes is not a function at checkAllergies

It is pointing to checkAllergies to tell us where the issue lies. But think about it this way, we created this variable to store a Boolean value to determine if the ingredient was included.

The checkAllergies function was meant to be either true or false, not a function name. And this may begin to confuse things in bigger projects. It may make sense to now change the variable name:

const includesBadIngredient = function (recipe, ingredient) {
  const hasIngredient = recipe.ncludes(ingredient);
  return hasIngredient;
};

And then we can give the function the checkAllergies name as intended:

const includesBadIngredient = function checkAllergies(recipe, ingredient) {
  const hasIngredient = recipe.ncludes(ingredient);
  return hasIngredient;
};

Since we changed the variable name, we need to update the function call:

console.log(includesBadIngredient(bread, 'salt'));

Now the error will point to the actual function name, not the variable. This now creates a clear separation between the stored return value and the function name.

Moving down to our second example section (comment out the first example):

// ===============================================
let posts = [
  { title: 'How to learn Javascript', body: 'bla bla bla' },
  { title: 'How to be a ninja', body: 'bla bla bla' },
  { title: 'How to be a ninja part 2', body: 'bla bla bla' },
];
const getIndex = posts
  .map(function (post) {
    return post.title.toUpperCase();
  })
  .findIndex(function (value) {
    return value === 'HOW TO BE A NINJA PART 2';
  });
console.log(getIndex);

This is the same example we used previously to look at array methods. There is an array of blog posts, and we then use two methods. First, we loop over the posts with map(), and transform the title to be upper case. And then chain onto the end the findIndex method to get a particular index number if there is a match.

Inferred function names

This section contains two anonymous functions inside the methods, so debugging may get difficult, especially if we have more nested inside.

This will log to the console the value of 2. But what if we had an error in our code like this:

const getIndex = posts
  .map(function (post) {
    return post.title.toupperCase();
  })
  .findIndex(function (value) {
    return value === 'HOW TO BE A NINJA PART 2';
  });

Here we use toupperCase() rather than toUpperCase(). This is easily done and something which can be hard to spot. Here is the error in the console, with the drop down arrow expanded:

index.html:40 Uncaught TypeError: post.title.toupperCase is not a function at index.html:40:24 at Array.map () at index.html:39:6 (anonymous) @ index.html:40 (anonymous) @ index.html:39

The console now points to an anonymous function where the issue lies. This is correct since it is an anonymous function, but we don’t even know which of the 2 anonymous functions it refers to. Is it the one inside map() or findIndex?

Of course, we can get some more clues below about the error location, but this can be complex if scripts are much longer and in multiple files. For this, we can again add names to our functions to keep it descriptive:

const getIndex = posts
  .map(function transformToUpper(post) {
    return post.title.toupperCase();
  })
  .findIndex(function getIndexFromTitle(value) {
    return value === 'HOW TO BE A NINJA PART 2';
  });

And this is kind of like adding a label to our function to help identify it, which we should now see in the console. This now specifically points to the transformToUpper function:

Uncaught TypeError: post.title.toupperCase is not a function at transformToUpper (index.html:40:24) at Array.map () at index.html:39:6

As with a lot of things, the decision of naming functions or leaving them as anonymous is your choice.

Often, it is not an issue to leave off the name and it can slightly reduce the amount of code. But, if you prefer to be more descriptive, and want extra debugging pointers you can add them to your functions.