JavaScript Function Expressions
Table of Contents + −
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:
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 variablegreet.- 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 declarationfunction add(a, b) { return a + b;}
// Function expressionconst subtract = function (a, b) { return a - b;};
console.log(add(5, 2)); // 7console.log(subtract(5, 2)); // 3Here is how the two forms compare in this code:
function add(a, b) { ... }is a declaration: it starts withfunctionand carries its own name,add.const subtract = function (a, b) { ... }is an expression: a nameless function saved into the variablesubtract.add(5, 2)andsubtract(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:
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:
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.
const applyDiscount = function (price) { return price * 0.9; // 10% off};
const cartTotal = 200;const finalPrice = applyDiscount(cartTotal);
console.log(finalPrice); // 180Let’s step through the calculator:
applyDiscountholds a function that takes apriceand returns it multiplied by0.9, which removes 10%.cartTotalis set to200, the amount before the discount.applyDiscount(cartTotal)runs the stored function with200, andfinalPricereceives 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!
- Create a function expression named
doublethat takes a number and returns it times two. - Call
doublewith a value and print the result. - Move the call above the definition and watch the error appear.
- 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.