# Function Hoisting vs Variable Hoisting in JavaScript: Key Differences Explained

> Understand function hoisting vs variable hoisting in JavaScript. Learn how function declarations are fully lifted while var variables are only initialized to undefined, boosting your code comprehension.

- Repository: [Kyle Simpson/You-Dont-Know-JS](https://github.com/getify/You-Dont-Know-JS)
- Tags: deep-dive
- Published: 2026-02-24

---

**Function hoisting lifts the entire function declaration (name and body) to the top of its scope, making it callable immediately, while variable hoisting (`var`) only lifts the identifier and initializes it to `undefined` until the assignment executes.**

JavaScript’s compilation phase registers identifiers before runtime execution begins. According to the *You Don't Know JS* book series by getify, this behavior—commonly called **hoisting**—operates differently for function declarations than for variables declared with `var`. Understanding these mechanics is critical for avoiding undefined values and ReferenceErrors in your code.

## What is Hoisting?

Hoisting refers to the compile-time action where the JavaScript engine registers variable and function declarations to their respective scopes before executing any statements. As detailed in [`scope-closures/ch5.md`](https://github.com/getify/You-Dont-Know-JS/blob/main/scope-closures/ch5.md), this process moves the "registration" of identifiers to the top of their enclosing **function** or **global** scope, though it behaves distinctly depending on whether the identifier is a function declaration or a variable.

## Function Hoisting: Declaration and Initialization

Function hoisting is the more aggressive of the two mechanisms. When the engine encounters a **function declaration** (not an expression), it hoists both the identifier and the function body to the top of the scope.

According to the source code in [`scope-closures/ch5.md`](https://github.com/getify/You-Dont-Know-JS/blob/main/scope-closures/ch5.md) (lines 33-35), *"A function declaration’s name identifier is registered at the top of its scope, and it’s additionally auto‑initialized to that function’s reference."*

This means you can invoke the function before its literal position in the code:

```javascript
// Call before the declaration – works because of function hoisting
greet();                 // → "Hello!"

function greet() {       // Function declaration
  console.log('Hello!');
}

```

Only **function declarations** (`function foo(){}`) appearing outside of block statements receive this treatment. Function expressions assigned to variables are subject to variable hoisting rules instead.

## Variable Hoisting with var

Variable hoisting behaves more conservatively. When the engine processes a `var` declaration, it registers the name at the top of the scope but initializes it to `undefined`. The actual assignment remains at its original runtime position.

As stated in [`scope-closures/ch5.md`](https://github.com/getify/You-Dont-Know-JS/blob/main/scope-closures/ch5.md) (lines 64-65): *"A `var` variable is also hoisted, and then auto‑initialized to `undefined`."*

This creates a "temporal gap" where the identifier exists but holds no useful value:

```javascript
console.log(num); // → undefined (variable hoisted, value not yet assigned)

var num = 42;     // Assignment happens at runtime

```

## Key Differences Between Function and Variable Hoisting

The distinction between these mechanisms affects when and how you can safely reference identifiers:

| Aspect | Function Hoisting | Variable Hoisting (`var`) |
|--------|-------------------|---------------------------|
| **What is hoisted?** | The *entire* function declaration (name **and** implementation). | Only the variable’s name; initialized to `undefined`. |
| **When can you use it?** | Immediately anywhere in the same scope, even before the declaration. | Anywhere, but reads return `undefined` until the assignment executes. |
| **Syntax requirements** | Only function declarations (`function foo(){}`) outside blocks. | Any `var` declaration regardless of position. |
| **Resulting behavior** | The identifier is bound to the function object immediately. | The identifier exists but yields `undefined` until assigned. |

**Function hoisting** enables a top-down coding style where you can place helper functions below the main logic and call them earlier. **Variable hoisting** can introduce subtle bugs because variables appear defined while actually holding `undefined`.

## Code Examples and Edge Cases

### Calling Functions Before Declaration

Function declarations are fully available throughout their scope:

```javascript
calculate(5, 3); // → 8

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

```

### The undefined Variable Behavior

Variables declared with `var` exist but contain no value until their line executes:

```javascript
console.log(message); // → undefined
var message = "Hello";
console.log(message); // → "Hello"

```

### Function Expressions Are Not Hoisted

Assigning a function to a `const` or `let` creates a function expression that follows variable hoisting rules (or Temporal Dead Zone rules for `let`/`const`), not function hoisting:

```javascript
try {
  shout();               // ReferenceError – not hoisted
} catch (e) {
  console.error(e);
}

const shout = function() {
  console.log('Hey!');
};

```

Only **function declarations** are hoisted; expressions behave like ordinary variable assignments where the identifier is not initialized until the line executes.

### When Function and Variable Names Collide

When both a function declaration and a `var` declaration share the same name, function hoisting takes precedence initially, but subsequent assignment overwrites it:

```javascript
console.log(foo); // → [Function: foo] (function hoisted first)

function foo() { console.log('function'); }
var foo = 10;    // var hoisted but doesn't re-initialize; assignment overwrites

foo();           // TypeError: foo is not a function (now holds the number 10)

```

The function declaration hoists first, giving `foo` a function value. The subsequent `var foo` declaration also hoists the name but does **not** re‑initialize it; the later assignment to `10` replaces the function reference.

## Summary

- **Function hoisting** moves the entire declaration (name + body) to the top of the scope and immediately binds the identifier to the function object, allowing invocation before the declaration line.
- **Variable hoisting** (`var`) registers only the identifier at the top of the scope and auto-initializes it to `undefined`, leaving the assignment for runtime execution.
- **Function expressions** (including arrow functions assigned to variables) are not hoisted as functions; they follow variable hoisting or Temporal Dead Zone rules depending on the declaration keyword.
- Both mechanisms are compile-time actions that affect runtime execution, but only function hoisting supplies the usable value instantly.

## Frequently Asked Questions

### Do let and const hoist like var?

No. While `let` and `const` declarations are technically registered during the compile phase, they are not initialized until their declaration statement is evaluated. They exist in the **Temporal Dead Zone** (TDZ) from the start of the block until the declaration line, causing a ReferenceError if accessed too early. This differs from `var`, which initializes to `undefined` immediately upon hoisting.

### Why can I call a function before declaring it but not access a variable?

Because function hoisting initializes the identifier immediately with the actual function reference, whereas variable hoisting initializes only with `undefined`. According to [`scope-closures/ch5.md`](https://github.com/getify/You-Dont-Know-JS/blob/main/scope-closures/ch5.md), function declarations are "auto‑initialized to that function’s reference" during the compile phase, while `var` declarations are "auto‑initialized to `undefined`" and must wait for runtime assignment.

### Are function expressions hoisted if I use var instead of const?

No. Whether you use `var`, `let`, or `const`, a function expression is treated as a variable assignment, not a function declaration. The variable identifier itself will hoist (with `undefined` for `var` or TDZ for `let`/`const`), but the function body is not available until the assignment statement executes.

### Is function hoisting considered good practice?

It depends on coding style preferences. The *You Don't Know JS* series notes in [`scope-closures/apA.md`](https://github.com/getify/You-Dont-Know-JS/blob/main/scope-closures/apA.md) that function hoisting enables a "top-down" readability style where main logic appears first and implementation details follow. However, many teams prefer declaring functions before use to avoid confusion, or they use function expressions to prevent accidental reliance on hoisting mechanics.