We use cookies to enhance your experience on the site
CodeWorlds

Hoisting

In Jurassic Park, some procedures are prepared before the workday begins - embryo storage is always ready, even before the first scientist arrives. JavaScript has a similar mechanism: hoisting moves certain declarations to the top of their scope before code execution.

Function Hoisting

Function declarations are fully hoisted - you can call them before they appear in code:

1// This works! The function is hoisted to the top
2sayHello();
3
4function sayHello() {
5  console.log('Hello from Jurassic Park!');
6}
7
8// Also works - hoisting moves the declaration before the call
9const danger = getDangerLevel();
10console.log(danger); // 'HIGH'
11
12function getDangerLevel() {
13  return 'HIGH';
14}

Function Expressions Are NOT Hoisted

1// This DOESN'T work - function expression is not hoisted
2// roar(); // TypeError: roar is not a function
3
4const roar = function() {
5  return 'ROOOAR!';
6};
7
8roar(); // Works here
9
10// Arrow functions also not hoisted
11// checkFence(); // ReferenceError: Cannot access 'checkFence' before initialization
12
13const checkFence = () => 'Fence OK';

var Hoisting

var
declarations are hoisted, but their values are NOT:

1console.log(dinoName); // undefined (not ReferenceError!)
2var dinoName = 'Rex';
3console.log(dinoName); // "Rex"
4
5// JavaScript sees it as:
6var dinoName; // declaration hoisted
7console.log(dinoName); // undefined
8dinoName = 'Rex'; // assignment stays in place
9console.log(dinoName); // "Rex"

var in Functions

1function checkZone() {
2  console.log(status); // undefined - var hoisted within function
3
4  if (true) {
5    var status = 'CLEAR';
6  }
7
8  console.log(status); // "CLEAR" - var is function-scoped
9}
10
11checkZone();

let and const - Temporal Dead Zone

let
and
const
ARE hoisted, but you can't access them before declaration. The period from start of scope to the declaration is called the Temporal Dead Zone (TDZ):

1// console.log(raptor); // ReferenceError: Cannot access 'raptor' before initialization
2let raptor = 'Blue';
3console.log(raptor); // "Blue"
4
5// const also has TDZ
6// console.log(danger); // ReferenceError!
7const danger = 'HIGH';

Why TDZ Exists

1// var can lead to bugs:
2function processData() {
3  console.log(result); // undefined - no error, but that's a bug!
4  // ... 200 lines of code ...
5  var result = computeResult();
6}
7
8// let/const catch errors early:
9function processDataBetter() {
10  // console.log(result); // ReferenceError - clear error message!
11  // ... 200 lines of code ...
12  let result = computeResult();
13}

Practical Example - Incident Management

1// Hoisting allows organizing code naturally
2function manageIncident(type, location) {
3  // We can call helper functions before they're defined
4  const severity = calculateSeverity(type);
5  const response = getResponseTeam(severity);
6
7  console.log(`Incident: ${type} at ${location}`);
8  console.log(`Severity: ${severity}`);
9  console.log(`Response team: ${response}`);
10
11  // Helper functions defined after usage - still works!
12  function calculateSeverity(incidentType) {
13    const severityMap = {
14      'ESCAPE': 5,
15      'INJURY': 4,
16      'EQUIPMENT_FAILURE': 3,
17      'MINOR': 1
18    };
19    return severityMap[incidentType] || 2;
20  }
21
22  function getResponseTeam(level) {
23    if (level >= 5) return 'Emergency team + Security';
24    if (level >= 3) return 'Security team';
25    return 'Maintenance';
26  }
27}
28
29manageIncident('ESCAPE', 'Zone A');
30// Incident: ESCAPE at Zone A
31// Severity: 5
32// Response team: Emergency team + Security

Class Hoisting

Classes are hoisted like

let
/
const
- they exist in TDZ:

1// const dino = new Dinosaur(); // ReferenceError!
2
3class Dinosaur {
4  constructor(name) {
5    this.name = name;
6  }
7}
8
9const dino = new Dinosaur('Rex'); // OK

Best Practices

1// 1. Declare variables at the top of their scope
2function goodPractice() {
3  const name = 'Rex';
4  let count = 0;
5  // ... use them below
6}
7
8// 2. Use const by default, let when you need to change the value
9const MAX_DINOSAURS = 100; // never changes
10let currentCount = 0;       // changes
11
12// 3. Avoid var - use let/const
13// Bad:
14var oldStyle = 'avoid this';
15// Good:
16const newStyle = 'use this';
17
18// 4. Functions can be defined after their usage
19// (but only function declarations, not expressions)

Hoisting Pitfalls

The Shadowing Trap

1function checkSecurity() {
2  var fenceStatus = "Offline"; // Hoisted to top of function
3
4  function enableFences() {
5    // This local variable is hoisted to top of enableFences,
6    // but doesn't shadow the outer variable until initialization
7    console.log("Current fence status before change:", fenceStatus); // undefined!
8
9    // Local fenceStatus shadows the one from outer scope
10    var fenceStatus = "Online";
11    console.log("New fence status:", fenceStatus); // "Online"
12  }
13
14  enableFences();
15  console.log("Fence status in main function:", fenceStatus); // "Offline" (unchanged)
16}
17
18checkSecurity();

In the above example, the

console.log
inside
enableFences
shows
undefined
because the local
fenceStatus
variable is hoisted but not yet initialized, shadowing the variable from the outer scope.

Better Approach with let/const

1function parkOperations() {
2  // Use const for values that shouldn't change
3  const maxVisitors = 2000;
4
5  // Use let for variables that may change
6  let currentVisitors = 0;
7
8  function admitVisitors(count) {
9    // With let/const, accessing a variable before declaration will throw an error,
10    // making it easier to detect potential problems
11
12    // This would throw an error:
13    // console.log(availableSpace);  // ReferenceError
14
15    // Declare first, then use
16    const availableSpace = maxVisitors - currentVisitors;
17    if (count <= availableSpace) {
18      currentVisitors += count;
19      console.log(`Admitted ${count} visitors. Currently in park: ${currentVisitors}`);
20      return true;
21    }
22
23    console.log(`Too many visitors! Available spots: ${availableSpace}`);
24    return false;
25  }
26
27  // Test our function
28  admitVisitors(500);  // Admitted 500 visitors
29  admitVisitors(1000); // Admitted 1000 visitors
30  admitVisitors(700);  // Too many visitors! Available spots: 500
31
32  return currentVisitors;
33}
34
35console.log(`Total visitors: ${parkOperations()}`);

Summary

Hoisting is an important concept in JavaScript that affects how code is executed:

  1. Function declarations are fully hoisted - you can use them before their declaration.
  2. var variables are hoisted with an
    undefined
    initialization - you can reference them, but they'll be
    undefined
    before initialization.
  3. let and const variables are hoisted but remain in the "temporal dead zone" - attempting access before declaration throws an error.
  4. Function expressions (assigned to variables) follow variable hoisting rules - the variable itself is hoisted, but the function assignment is not.

"Hoisting in JavaScript is like morning park setup" - says Dr. Rex. "Before visitors arrive (before code runs), certain preparations are done automatically - protocols are ready, procedures are in place. But the actual data (values) must still be prepared in real time!"

Go to CodeWorlds