Function Expressions

Open the project folder

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

03.Functions > 02.Function-expressions

Function declarations

We have created functions so far using a syntax called a function declaration. There is also a slightly modified way to write functions called function expressions.

In the starter files, we have a familiar example of a function declaration:

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

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

Creating function expressions

The alternative function expression looks similar. The first difference is the way we name the function. To transform this into an expression, we can remove the function name. This is optional but more on this later:

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

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

Then we assign it to a variable, and log to the console:

const checkAllergies = function(recipe, ingredient) {
  const hasIngredient = recipe.includes(ingredient);
  return hasIngredient;
};
console.log(checkAllergies(bread, 'flour'));

Leaving the name out like this is optional, but it is now an anonymous function because of the lack of name.

Introduction to hoisting

This storing in a variable is a difference between a function declaration and an expression, another is something called hoisting. Hoisting is something we cover later in more detail but for now, it allows us to call a function before we create it. It behaves like our function is declared at the top of the file.

If we move the console log to be above the function, will it work?

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

console.log(checkAllergies(bread, 'flour'));

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

JavaScript programs are read from the top, so we are calling the checkAllergies function before we know it exists.

The console will throw an error:

Uncaught ReferenceError: Cannot access 'checkAllergies' before initialization

This means for functions expressions we must call functions after they are created. But what about the original function? Give this a try by removing the comments from the first function, and commenting out the second:

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

console.log(checkAllergies(bread, 'flour')); // true

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

This one should work. The means the first function syntax, the declaration, can be called before we create it, and this is another difference. This original function declaration is available anywhere because it is available on the global scope. Just like in the previously, we can access the window to see this. First, we need to make a few changes.

// Uncomment both functions so they are available:
function checkAllergies(recipe, ingredient) {
  const hasIngredient = recipe.includes(ingredient);
  return hasIngredient;
}

// Re-name function to avoid errors:
const checkAllergies2 = function (recipe, ingredient) {
  const hasIngredient = recipe.includes(ingredient);
  return hasIngredient;
};

Now both functions are active, over to the console where we can access functions on the window object.

window.checkAllergies // returns the function
window.checkAllergies2 // undefined

This can be important to consider since we don’t always want to pollute the global scope unless we need to. An example of this can be a callback function, a callback is a function passed to another function, like when we looked at array methods.

If we consider this example, which is just going to be a function to take a string, and make it upper case:

function toUpper(value) {
  return value.toUpperCase();
}
console.log(toUpper('flour')); // FLOUR

Nothing we have not seen before, and if we check this in the console:

window.toUpper

We get back a function, so this is available globally. This is fine if global access is required, but, this is not always needed. An example of this would be using the toUpper function with an array method:

bread.map(toUpper);

This will run the toUpper function for each array value, transforming them to be upper case. Only using the function like this will not require global scope.

Recap

To recap, a function declaration is constructed using the function keyword, a function name with optional parameters, and all the code inside of curly braces.

The function expression, as we have just looked at, is stored into a variable. And can also have an optional function name too.