Toggle theme D

Code repetition is the enemy. You write the same logic in ten places, then you need to change it, and now you're hunting through every file. Functions solve this — they're named blocks of code you can reuse by calling them whenever you need.

function greet(name) {
  return 'Hello, ' + name;
}

console.log(greet('Alice'));  // 'Hello, Alice'
console.log(greet('Bob'));    // 'Hello, Bob'

One definition, unlimited use. But JavaScript gives you two ways to write functions, and they're not quite the same.

Function Declaration

A function declaration defines a named function:

function add(a, b) {
  return a + b;
}

This creates a function called add that takes two parameters and returns their sum. You can call it anywhere in your code after this definition appears.

Function Expression

A function expression assigns a function to a variable:

const add = function(a, b) {
  return a + b;
};

The function here is anonymous — it has no name. It gets assigned to the variable add, and you call it using that variable.

You can also name function expressions if you want:

const factorial = function fact(n) {
  if (n <= 1) return 1;
  return n * fact(n - 1);
};

The name fact is only available inside the function itself — useful for recursive calls.

Side-by-Side Comparison

AspectDeclarationExpression
Syntaxfunction name()const name = function()
Named or anonymousAlways namedCan be either
HoistingFully hoistedVariable hoisted, not value
Where in codeAnywhere in scopeMust be defined before use

The biggest practical difference comes down to hoisting.

Hoisting: Why It Matters

JavaScript processes your code before running it. During this preparation phase, it "hoists" — pulls to the top — function declarations and variable declarations. But there's a catch with function expressions.

console.log(add(2, 3));  // 5 — works!

function add(a, b) {
  return a + b;
}

Function declarations are hoisted entirely. You can call them before they appear in your code because the entire function gets moved to the top of scope during processing.

Now try the same with a function expression:

console.log(multiply(2, 3));  // TypeError: multiply is not a function

const multiply = function(a, b) {
  return a * b;
};

This fails. The variable multiply is hoisted (so you don't get a ReferenceError), but it's undefined until the assignment runs. Calling undefined() throws a TypeError.

The fix is straightforward: define your function expressions before you call them.

const multiply = function(a, b) {
  return a * b;
};

console.log(multiply(2, 3));  // 6 — now it works

When to Use Each

Use declarations when:

  • You need the function available anywhere in the scope

  • The function is self-contained and doesn't depend on external state

  • You want maximum flexibility with call order

Use expressions when:

  • You're assigning functions to variables or properties

  • You're passing functions as arguments to other functions

  • You need anonymous functions for one-off use (callbacks, array methods)

// Function expression passed as a callback
setTimeout(function() {
  console.log('This runs after 1 second');
}, 1000);

// Function expression with array method
const numbers = [1, 2, 3, 4, 5];
const doubled = numbers.map(function(n) {
  return n * 2;
});

Modern JavaScript has arrow functions, which are a compact form of function expressions:

const doubled = numbers.map(n => n * 2);

Arrow functions are worth learning separately, but under the hood they're still expressions.

Practice Assignment

Try these exercises to reinforce the concepts:

  1. Write a function declaration that multiplies two numbers

  2. Write the same logic as a function expression

  3. Call both functions and print the results

// Declaration
function multiply(a, b) {
  return a * b;
}

// Expression
const multiply = function(a, b) {
  return a * b;
};

console.log(multiply(3, 4));      // 12
console.log(multiply(5, 6));      // 30

Now test hoisting. Try calling multiply before the expression definition and after:

// Before definition — fails
try {
  console.log(multiply(2, 2));  // TypeError
} catch (e) {
  console.log('Failed before definition');
}

// Expression defined here
const multiply = function(a, b) {
  return a * b;
};

// After definition — works
console.log(multiply(2, 2));  // 4

Wrapping Up

The difference comes down to hoisting and syntax. Function declarations are fully hoisted and always named. Function expressions are assigned to variables, can be anonymous, and require the variable to be defined before use.

For most code, either works. The choice becomes meaningful when you're passing functions around (callbacks, array methods) or need to be precise about when a function is available. Get comfortable with both forms — you'll see both in real codebases.