All topics
Functionsbeginner

Function Hoisting and Declaration vs Expression

How function declarations, function expressions, and named function expressions differ in hoisting behavior and use cases.

Three ways to define a function, and they differ in when the name is usable.

A function declaration is like a fully-built house that's already standing when you arrive, ready to walk into. A function expression is like an empty lot with a sign showing whose house will eventually be built there — the sign (variable name) exists early, but you can't move in (call it) until construction (the assignment) actually finishes.

Key Concepts

1
    function declared() {}              // declaration
    const expr = function () {};        // expression
    const named = function inner() {};  // named expression
    const arrow = () => {};             // arrow expression
2
Only the declaration is available before its line.
    declared();   // works
    expr();       // TypeError: expr is not a function
    arrow();      // ReferenceError -- TDZ
3
    function declared() {}
    var expr = function () {};
    const arrow = () => {};
4
The declaration is hoisted whole. An expression follows its variable's rules, so var gives undefined and const throws.
varundefinedconst
5
The named function expression has a use. The inner name is visible only inside the function:
6
    const fact = function f(n) {
      return n <= 1 ? 1 : n * f(n - 1);    // f, not fact
    };
7
    f;   // ReferenceError outside
8
That matters because fact could be reassigned, and the recursion would break. Referring to the inner name is safe. It also gives the function a proper name in stack traces, which anonymous expressions do not.
fact
9
Declarations inside blocks are the edge case.
    if (true) {
      function g() {}
    }
    g();   // works in modern strict mode? depends
10
Behaviour has differed between engines and between strict and sloppy mode. Declare functions at the top level of a scope, or use an expression — the ambiguity is not worth navigating.
11
Which to use.
    a top-level utility        declaration -- hoisting is harmless
                               and the name appears in traces
    a callback or a value      arrow
    a method on an object      the method shorthand
    recursive, assigned to a
      variable                 named expression
12
The practical point. Hoisting lets you call a declared function before defining it, and doing so deliberately makes code harder to follow.
13
Its real value is that a file of helper functions does not need to be ordered by dependency — which is a convenience, not a technique.
14
What the interviewer is probing.1. "Which can you call before its line?" Probing: the difference. Stalls: "Both." *Moves up:* a declaration, which is fully hoisted; an expression assigned to a variable is not and throws TypeError.
15
2. "Are function declarations hoisted out of blocks?" Probing: the messy corner. Stalls: "Yes, like var." Moves up: in strict mode and modules they are block-scoped; the legacy sloppy-mode behaviour differed between engines, which is why it is avoided.
16
3. "Why prefer const with an arrow function?" Probing: the argument. Stalls: "Style." *Moves up:* it cannot be reassigned or used before definition, so the temporal dead zone turns an ordering mistake into an immediate error.
17
4. "What is a named function expression for?" Probing: the small benefit. Stalls: "Nothing." Moves up: the name is visible inside for recursion and appears in stack traces, without leaking into the enclosing scope.