4) Conditionals, Loops and Functions Lesson

Anonymous Functions and Function Expressions in JavaScript

13 min to complete · By Ian Currie

In the dynamic world of JavaScript, functions are the building blocks of code, allowing programmers to encapsulate tasks into reusable pieces. They come in two main flavors: declarations, which is the typical function definition you've covered in previous lessons, and expressions, which can be anonymous.

This distinction is subtle yet significant, laying the groundwork for sophisticated patterns in coding, including the use of arrow functions and callbacks that are central to modern JavaScript's asynchronous programming model. Understanding these concepts is a stepping stone to mastering the language's full potential. This lesson lays some groundwork for understanding later lessons in this course like Understanding Asynchronicity in JavaScript

What Is the Difference Between Declared Functions and Expressed Functions

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

Do you notice the difference in syntax from function declaration?

This function can be invoked in exactly the same way:

greet("Nomad"); // "Hello, Nomad"

Declared Functions

Here are some key features of declared functions:

  • They are defined using the function keyword followed by the function name
  • You can call them before they appear in the code, that is, they are hoisted

In JavaScript, a hoisted function is a function declaration that can be used before it's written in the code. Here's a simple example:

// Call the function before it's defined in the code
sayHello(); // "Hello there!"

// Function declaration that gets hoisted
function sayHello() {
  console.log("Hello there!");
}

When the JavaScript runs, it first reads through the entire file and moves all function declarations to the top, making them available anywhere in their scope. This is known as "hoisting." So even though we call sayHello() before we write out the function, JavaScript knows about the function because it's been hoisted to the top during the initial read-through. There's more information on hoisting and scope in a later lesson in this course, The Basics of Scope in JavaScript.

Expressed Functions

In contrast to a function declaration, a function expression is not hoisted and thus must be defined before you can use it. Here's an example:

// Trying to call the function expression before it's defined will result in an error
sayHello(); // This will cause a TypeError: sayHello is not a function

// Function expression is assigned to a variable
let sayHello = function() {
  console.log("Hello there!");
};

// Now you can call the function after it's defined
sayHello(); // This will correctly log "Hello there!" to the console

In this case, because sayHello is a function expression assigned to a variable, JavaScript does not move the definition to the top of the scope. The function only exists after the interpreter reaches the assignment line, making it available for use from that point onward.

Why are these functions associated with so-called "anonymous" functions? Read on to find out more.

Functions as Parameters of Other Functions

Sometimes you will be faced with a function that takes in another function as a parameter. The function-as-argument is often called a callback function. This is the case with the function setTimeout(). This function has two parameters, one is the function to execute, one is the time in milliseconds, defined in the second parameter, is finished.

setTimeout(  function , timeInMilliseconds  )

When a function takes in a function as an argument, the function argument is often called a callback. The setTimeout() function will callback the function argument once it's ready to do so.

Colorful illustration of a light bulb

You may have noticed that you don't have to define the setTimeout() function, its already defined out-of-the-box, it is built-in to the browser JavaScript environment, as are many other functions.

Examine the following snippet to see how this looks in action:

// Define the function
function timeIsUpMessage() {
  console.log("Time is up!");
}

// Use the function as an argument.
setTimeout(timeIsUpMessage, 3000);

While further developing this program, you may notice that the function timeIsUpMessage is only going to be used as part of this single setTimeout call, so its a bit inconvenient to have the function defined apart from it. If you wanted to modify the message, you would need to check the function name in setTimeout and then search for the function.

As programmers, it is essential that these little inconsistencies are taken care of, because they pile up so quickly by the time you realize what has happened you've got bugs all over the place. So, depending on the situation, it can be more concise to define your function like this:

setTimeout(function () {
  console.log("Time is up");
}, 3000);

Now, your code is all packaged up in one block. You no longer have to have knowledge of a function that may be many lines apart from where it's used. Optimizing code for conciseness can be satisfying!

A Brief Introduction to Arrow Functions

The syntax for an anonymous function within setTimeout in the previous example can be further shortened with an arrow function:

setTimeout(() => console.log("Time is up"), 3000);

Arrow functions are another way to write a function expression, which you'll explore more in later lessons, such as Basics of Arrow Functions in JavaScript.

To sum up the example above:

  • The code calls a setTimeout() function.
  • For the first argument, you express a function that will console.log the message "Time is up".
  • For the second argument, you use 3000 milliseconds as the time to wait.
  • So when this code is run, the message "Time is up" will be logged to the console after 3 seconds.

It's a nice one liner! For simple tasks like this, one liners can make things very concise while not needing to sacrifice legibility.

Colorful illustration of a light bulb

Some programmers enjoy the challenge of writing code that uses the least number of characters to complete a task; this is known as "code golf." However, this type of ultra-concise code can be very difficult to understand for most people. While it might save a bit of space in the source code, it can be a nightmare to update or fix later, often for the original author themselves.

Anonymous Functions

The two styles of function expressions in JavaScript, anonymous and named, behave similarly. Anonymous functions resemble the function declarations you've seen before but lack a name. Such functions are considered "anonymous" because they cannot be referenced or called by name outside of their immediate context, like within a setTimeout call, unless they are assigned to a variable or given an explicit name.

You can also attach a function expression to a variable, and call it like a normal function:

let sayHello = () => console.log("hello");
sayHello(); // "hello"

Writing functions with arrow functions like this can be useful in certain situations (apart from their conciseness), but don't worry about why just now—you don't need to know the subtle differences at this stage.

You can also write functions that are anonymous:

setTimeout(() => console.log("Time is up"), 3000);

The function that logs "Time is up" is not callable from anywhere because there's no reference to it. It has no name, and so can be considered anonymous.

Summary: Function Expressions and Anonymous Functions in JavaScript

  • Functions in JavaScript can be declared or expressed, with the latter allowing for anonymous functions without declared names.
  • Function expressions must be defined before they are called, unlike declared functions which can be called beforehand due to hoisting.
  • Using function expressions can pave the way for understanding arrow functions and more advanced coding concepts.
  • Function expressions are useful when functions are used as parameters, such as in setTimeout(), allowing for more concise code.
  • Anonymous function expressions can be assigned to variables and called like regular functions.
  • While concise code is beneficial, overly terse code, like that seen in "code golf," can be hard to maintain and understand.