Async Awaits Logo

AsyncAwaits

Why does var log undefined but functions work before declaration in JavaScript ?

clock icon

asked 2 weeks ago

message icon

1

eye icon

116

I’m learning JavaScript and came across the concept of hoisting, but I’m still confused about how it actually works.

When I run this code:

1console.log(num);
2var num = 10;
3
4console.log(greet?.());
5function greet() {
6 return "Hello, World!";
7}
8
1console.log(num);
2var num = 10;
3
4console.log(greet?.());
5function greet() {
6 return "Hello, World!";
7}
8

I get this output:

1undefined
2Hello, World!
3
1undefined
2Hello, World!
3

This behavior feels strange to me. I expected the first console.log(num) to throw an error since num hasn’t been defined yet, but instead it prints undefined. On the other hand, the greet function works perfectly fine even though I call it before declaring it.

Can someone explain why variables declared with var behave differently from functions? And how does this change if I use let or const instead of var?

1 Answer

Filters

The behavior you're observing is a core aspect of JavaScript's hoisting mechanism, which applies differently to var declarations and function declarations.

Here's a breakdown:

Hoisting of var Variables

When JavaScript processes your code, var declarations are "hoisted" to the top of their scope (global or function scope). However, only the declaration is hoisted, not the assignment. Crucially, var variables are also initialized with undefined during the hoisting phase.

Consider your code:

1console.log(num); // Line 1
2var num = 10; // Line 2
1console.log(num); // Line 1
2var num = 10; // Line 2

JavaScript interprets this as if it were:

1var num = undefined; // Declaration and initialization are hoisted
2console.log(num); // num is currently undefined
3num = 10; // Assignment happens later
1var num = undefined; // Declaration and initialization are hoisted
2console.log(num); // num is currently undefined
3num = 10; // Assignment happens later

That's why console.log(num) on the first line outputs undefined instead of throwing an error. The variable num exists, but its assigned value of 10 hasn't been reached yet.

Hoisting of function Declarations

In contrast, function declarations are hoisted in their entirety – both the function's name and its body are moved to the top of their scope. This means the entire function is available for use before it appears in the code.

For your greet function:

1console.log(greet?.()); // Line 1
2function greet() { // Line 2
3 return "Hello, World!";
4}
1console.log(greet?.()); // Line 1
2function greet() { // Line 2
3 return "Hello, World!";
4}

JavaScript effectively processes this as:

1function greet() { // Entire function is hoisted
2 return "Hello, World!";
3}
4console.log(greet?.()); // Function is fully available and can be called
1function greet() { // Entire function is hoisted
2 return "Hello, World!";
3}
4console.log(greet?.()); // Function is fully available and can be called

This allows greet() to be invoked successfully on the first line, returning "Hello, World!".

Summary of Differences

  • var variables: Declaration is hoisted, initialized to undefined. Assignment stays in place.
  • function declarations: Entire function (declaration and definition) is hoisted, making it fully available.

How let and const Differ

let and const also experience hoisting, but they behave differently from var:

  1. No Default Initialization: While their declarations are hoisted, let and const variables are not initialized to undefined.
  2. Temporal Dead Zone (TDZ): If you try to access a let or const variable before its actual declaration in the code, JavaScript will throw a ReferenceError. This period between the start of the scope and the actual declaration is called the Temporal Dead Zone.

Example with let and const:

1// console.log(a); // ReferenceError: Cannot access 'a' before initialization (TDZ)
2let a = 10;
3console.log(a); // 10
4
5// console.log(b); // ReferenceError: Cannot access 'b' before initialization (TDZ)
6const b = 20;
7console.log(b); // 20
1// console.log(a); // ReferenceError: Cannot access 'a' before initialization (TDZ)
2let a = 10;
3console.log(a); // 10
4
5// console.log(b); // ReferenceError: Cannot access 'b' before initialization (TDZ)
6const b = 20;
7console.log(b); // 20

This behavior of let and const helps catch potential bugs related to accessing uninitialized variables and makes JavaScript code more predictable, which is why let and const are generally preferred over var in modern JavaScript.

Write your answer here

Top Questions