definition
function
javascript

var functionName = function() {} vs function functionName() {}

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

JavaScript supports both function declarations and function expressions, and they are not interchangeable in all situations. The biggest differences are hoisting behavior, naming, and how each form behaves in modern module code. Understanding those differences helps you avoid runtime surprises and write predictable APIs.

Function Declaration Versus Function Expression

A function declaration defines a named function directly in scope:

javascript
function greet(name) {
  return `Hello, ${name}`;
}

A function expression creates a function value and assigns it to a variable:

javascript
var greet = function (name) {
  return `Hello, ${name}`;
};

Both can be called as greet("Ada"), but setup timing is different.

Hoisting Differences

Function declarations are hoisted with their implementation, so they can be called before their textual definition.

javascript
1console.log(sum(2, 3)); // 5
2
3function sum(a, b) {
4  return a + b;
5}

With var function expressions, only the variable declaration is hoisted, not the function assignment.

javascript
1console.log(sum); // undefined
2// console.log(sum(2, 3)); // TypeError: sum is not a function
3
4var sum = function (a, b) {
5  return a + b;
6};

With let or const, the binding is in temporal dead zone before initialization.

javascript
1// console.log(sum); // ReferenceError
2
3const sum = function (a, b) {
4  return a + b;
5};

This is one reason modern code often prefers explicit ordering over relying on hoisting.

Naming and Debugging Behavior

Function declarations always have a name, which improves stack traces. Function expressions can be anonymous or named.

Named expression example:

javascript
1const factorial = function factorialImpl(n) {
2  if (n <= 1) return 1;
3  return n * factorialImpl(n - 1);
4};
5
6console.log(factorial(5)); // 120

The inner name factorialImpl is useful for recursion and debugging, while external callers use factorial.

Scope and Block Behavior

In modern JavaScript, function declarations inside blocks can have engine-specific historical quirks in non-strict contexts. In strict mode and modules, behavior is more predictable, but style consistency still matters.

Function expressions assigned to const inside blocks are explicit and avoid legacy edge cases.

javascript
1if (true) {
2  const say = function () {
3    return "inside block";
4  };
5  console.log(say());
6}

For maintainability, many teams prefer function declarations for top-level reusable helpers and const function expressions for callbacks and closures.

Callbacks and Higher-Order Patterns

Function expressions are common when functions are passed as values.

javascript
1const numbers = [1, 2, 3, 4];
2
3const doubled = numbers.map(function (n) {
4  return n * 2;
5});
6
7console.log(doubled); // [2, 4, 6, 8]

Arrow functions are a modern shorthand for many expression use cases:

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

Function declarations are still useful when you want named, hoisted utilities with clear signatures.

Practical Recommendation in Modern Code

A practical style guide that works well:

  • Use function declarations for core named utilities in a module.
  • Use const function expressions for values passed around as data, especially callbacks.
  • Avoid var in new code due to function scope and hoisting confusion.

Example mixed style:

javascript
1function parseUser(raw) {
2  return { id: Number(raw.id), name: String(raw.name) };
3}
4
5const isValidUser = function (user) {
6  return Number.isInteger(user.id) && user.name.length > 0;
7};
8
9const users = [{ id: "1", name: "Ada" }, { id: "x", name: "" }]
10  .map(parseUser)
11  .filter(isValidUser);
12
13console.log(users); // [{ id: 1, name: "Ada" }]

This pattern keeps intent clear and avoids hoisting-related confusion.

Common Pitfalls

A common pitfall is calling a var function expression before assignment and assuming it behaves like a declaration. Another is using var in modern codebases and introducing hard-to-track scope behavior. Teams also overuse anonymous expressions, which can reduce stack trace clarity during debugging. Confusion around block-level function declarations in mixed strict and non-strict environments can create subtle bugs. Finally, inconsistent style across a codebase makes readability and onboarding harder.

Summary

  • Function declarations and function expressions differ mainly in hoisting and declaration timing.
  • Declarations are hoisted with implementation, while expression assignments happen at runtime.
  • Prefer const function expressions over var in modern JavaScript.
  • Use declarations for reusable named helpers and expressions for callback-style values.
  • Pick a consistent team style to reduce runtime surprises and improve maintainability.

Course illustration
Course illustration

All Rights Reserved.