JavaScript Function Expressions

In the previous lesson, we learned how functions send back results with return. Now let’s look at another way to create functions: storing them in variables with function expressions.

📦 Functions Are Values

In JavaScript, a function is a value, just like a number or a string. That means we can store a function inside a variable. When we do that, we have written a function expression.

Here is a function stored in a variable:

function-expressions.js
const greet = function () {
console.log("Hello!");
};
greet(); // Hello!

Let’s walk through what each part does:

  • const greet = function () { ... } creates a function and saves it in the variable greet.
  • The function body, console.log("Hello!"), is the work that runs when we call it.
  • greet() runs the stored function by putting parentheses after the variable name, exactly like we call any other function.

The function on the right side has no name of its own. We call this an anonymous function, which means a function without a name. The variable greet is how we reach it.

The semicolon at the end

A function expression is an assignment, so it ends with a semicolon, just like const x = 5;. The closing } is followed by a ;.

🆚 Declaration vs Expression

We have already seen function declarations in earlier lessons. A function declaration starts with the function keyword and gives the function a name. A function expression stores a function in a variable instead.

Here are both side by side:

function-expressions.js
// Function declaration
function add(a, b) {
return a + b;
}
// Function expression
const subtract = function (a, b) {
return a - b;
};
console.log(add(5, 2)); // 7
console.log(subtract(5, 2)); // 3

Here is how the two forms compare in this code:

  • function add(a, b) { ... } is a declaration: it starts with function and carries its own name, add.
  • const subtract = function (a, b) { ... } is an expression: a nameless function saved into the variable subtract.
  • add(5, 2) and subtract(5, 2) call each one the same way, and both return their result.

Both functions do their job the same way once they run. The difference is in how we create them and when JavaScript makes them available.

Feature Function Declaration Function Expression
How it starts function add() {} const add = function () {};
Has a name Yes, after function Usually anonymous; the variable holds it
Ends with a semicolon No Yes
Available before its line Yes (hoisted) No (not hoisted)

🪝 The Hoisting Difference

Hoisting is the way JavaScript moves function declarations to the top of the file before running the code. Because of hoisting, we can call a function declaration before the line where we wrote it.

This works because the declaration is hoisted:

function-expressions.js
sayHi(); // Hi there! (works)
function sayHi() {
console.log("Hi there!");
}

Let’s trace what happens here:

  • sayHi() runs on the first line, before the function is written.
  • function sayHi() { ... } is a declaration, so JavaScript hoists it to the top before running anything.
  • Because it is already available, the early call works and prints Hi there!.

A function expression is not hoisted in the same way. The variable exists, but it does not hold the function until that line runs. So calling it too early gives an error:

function-expressions.js
sayBye(); // ❌ Error: Cannot access 'sayBye' before initialization
const sayBye = function () {
console.log("Goodbye!");
};

Let’s trace why this one breaks:

  • sayBye() runs on the first line, before the assignment below it.
  • const sayBye = function () { ... } does not assign the function until that line is reached.
  • So the early call fails with Cannot access 'sayBye' before initialization.

Order matters with expressions

With a function expression, always define it before you call it. We will explore hoisting in more depth in a later lesson.

🛠️ A Practical Example

Storing functions in variables is handy when we want to pick a function based on a choice. Here Alex builds a tiny price calculator that applies a discount.

function-expressions.js
const applyDiscount = function (price) {
return price * 0.9; // 10% off
};
const cartTotal = 200;
const finalPrice = applyDiscount(cartTotal);
console.log(finalPrice); // 180

Let’s step through the calculator:

  • applyDiscount holds a function that takes a price and returns it multiplied by 0.9, which removes 10%.
  • cartTotal is set to 200, the amount before the discount.
  • applyDiscount(cartTotal) runs the stored function with 200, and finalPrice receives the result, 180.

Because the function lives in a variable, we can pass it around or swap it for a different one later, which is something we will use often with arrow functions and callbacks.

⚠️ Common Mistakes to Avoid

Mistake Problem Solution
Calling the expression too early It is not hoisted, so you get an error Define the function before you call it
Forgetting the semicolon An assignment should end with ; Add ; after the closing }
Confusing the two forms Expecting an expression to act like a declaration Remember: only declarations are hoisted

🔧 Try It Yourself!

  1. Create a function expression named double that takes a number and returns it times two.
  2. Call double with a value and print the result.
  3. Move the call above the definition and watch the error appear.
  4. Write a function declaration that does the same thing, and notice you can call it before its line.

🧩 What You’ve Learned

  • ✅ Functions are values, so we can store them in variables
  • ✅ A function expression looks like const greet = function () { ... };
  • ✅ A function expression usually uses an anonymous function and ends with a semicolon
  • ✅ Function declarations are hoisted, but function expressions are not
  • ✅ Always define a function expression before you call it

🚀 What’s Next?

Now that we can store functions in variables, let’s learn a shorter, modern way to write them. Let’s continue to Arrow Functions.

Share & Connect