Understanding JavaScript scope

🕑 2 minute read

Scope refers to which functions, variables and objects other functions, variables and objects are able to access when an application is run. It can seem confusing at first, but with a slightly strange example I will try and explain the basics unsing castles and emojis 🤔...

Global and local scope

Imagine a castle. There is the land outside the castle which is global, and there is the land inside the castle which is local. People in the castle can see out into the countryside and see what exists outside in global, but people from global can't see into the castle's local environment.

let barbarian = "😈"; // Barbarians roam everywhere outside. Be careful!

function castleWalls () {
    let guard = "🥷"; // We have a few guards in the walls to protect us
    console.log([guard, barbarian]) // => ["🥷", "😈"]
}

castleWalls(); 

console.log(barbarian) // => "😈"
console.log(guard) // => `Uncaught ReferenceError: guard is not defined`

barbarian is global, and guard is local to the castleWalls. What that means is that anything within the castleWalls can "see" what is within itself, and what is on the outside.

  • The castleWalls scope allows it to see the local guard AND the global barbarian.
  • The global scope cannot see the guard (because they hide behind the castleWalls!).

Multiple local scopes

Each function has it's own local scope but can't see into the local scope of others.

let barbarian = "😈";

function castleWalls () {
    let guard = "🥷";
}

function village () {
    let villager = "👩‍🌾";
    console.log(villager); // => "👩‍🌾"
    console.log(barbarian); // => "😈"
    console.log(guard); // => `Uncaught ReferenceError: guard is not defined`
}

Just as the barbarians cannot see into the castleWalls, the same applies to the village.

  • The village can see the global barbarian and it's own local villager.
  • The village cannot see into the guard because it is local/inside the castleWalls.
  • The castleWalls is separate from the village, it cannot see into the village so it cannot see villager.

Essentially, everything can see out of it's own scope, but not into the scope of others, unless it is created inside of the other scope.

Nested local scope

A bit like in Inception, there are multiple levels of local scope. Each nested code block (for loop, function etc) has it's own scope. When these are nested within each other you end up with muliple levels of of local scope.

In the following example each "area" within the castle also has it's own local scope. A castle needs a inner wall, and a tower, so let's build them. They can see outwards, but not inwards.

let barbarian = "😈";

function castleWalls () {
    let guard = "🥷";
    
    function innerWalls () {
        let archer = "🏹️";
    
        function tower () {
            // The king is here! Long live the king!
            let king = "🤴"
            console.log("Tower: ", [king, archer, guard, barbarian])
            // => "Tower: " ["🤴", "🏹️", "🥷", "😈"]    
        }
        
        console.log("innerWalls: ", [archer, guard, barbarian])
        // => "innerWalls: " ["🏹️", "🥷", "😈"]
        tower();
    }
  
    console.log("outerWalls: ", [guard, barbarian]);
    // => "outerWalls: " ["🥷", "😈"]
    innerWalls()
}

console.log("global: ", [barbarian]) // => "global: " ["😈"]
castleWalls();
  • In the tower, the king can see (has access to the scope of) the local tower.
  • He also can see out from the tower and into the innerWalls (local), the castleWalls (local) and into the surrounding countryside (global).
  • In the innerWalls, the archers cannot see the king, but they can see the castleWalls and their local guard and can see out to the surrounding countryside (global scope).
  • The barbarians can see nothing other than themselves or anything else in the global scope.

Because everything within a scope gains that scope for itself it means that a nested block of code will gain the scope it has been created in. tower gains the scope of innerWalls because it has been created within inner walls. This continues up the chain until you reach the global scope.

If you try to access king, archer, or guard from outside the castle you will get Uncaught ReferenceError: king is not defined because the global scope has no visibility inside the walls, or tower.

Note: Luckily in these example we have ninjas on guard, so the king is safe. Long live the king! 🤴