Nesting Scope

Open the project folder

In our starter files, open the index.html page from this lessons folder:

09.Scope-Hoisting-Closures > 02.Nesting-scope

Lexical scope

So far, we discovered scope only appears to work one way, from outside to inside. Variables declared at the top, global level, are available inside of other functions or blocks.

We can carry on by nesting other statements inside of others, and the scope continues in the same way. Access is passed down to each level, yet new variables declared inside of new blocks are restricted, they are effectively not passed back up to outer levels.

This scope nesting is referred to as lexical scope in JavaScript and many other languages.

Extending our example

To begin, we have the same setup as previously used:

var score = 0;
function updateScore() {
  score++;
  var bonus = 10;
  console.log(score + bonus);
}
updateScore();

First, change the console log so we know where we are because we are going to be extending this code:

console.log('inside function’);

Then still inside the function, nest another block, such as an if statement:

function updateScore() {
  score++;
  var bonus = 10;
  console.log('inside function');
  // create if statement inside of function
  if (bonus) {
    console.log('inside if statement: ' + bonus);
  }
}

This if statement is trying to access the bonus variable from the outer scope, what do you think will happen?

Variable access from the outer scope

This will work fine. Nested statement blocks can access variables from the outer scope, but what about the other way around? Let's take a look:

function updateScore() {
  score++;
  var bonus = 10;
  // 2. try to log bonus2 from a level above
  console.log('inside function ' + bonus2);
  if (bonus) {
    // 1. create new nested var
    var bonus2 = 20;
    console.log('inside if statement: ' + bonus);
  }
}

The result will be undefined, meaning this does not work the other way around. We get undefined meaning the variable exists, but it is assigned an undefined value.

Side note: If bonus2 was declared with let or const, it would throw an error rather than having the undefined value, but more on this soon.

Going deeper

The nesting can also continue as deep as we want to go, let’s try another block statement, the while loop. This also has its own curly braces to enclose the code, and create a new, inner scope.

Remove the bonus2 variable, along with the console log referring to this variable.

Add the while loop inside the if statement:

function updateScore() {
  score++;
  var bonus = 10;
  if (bonus) {
    console.log("inside if statement: " + bonus);
    var numbers = [1, 5, 8, 2];
    var i = 0;
    // create while loop:
    while (i < numbers.length) {
      console.log(numbers[i]);
      i++;
    }
  }
}

This works fine, the console will display the numbers from the outer block. And you can probably guess what happens if we create a new variable in the while loop, and access it on an outer level:

function updateScore() {
  score++;
  var bonus = 10;
  // 2. Log bonus3 in outer scope
  console.log("inside function " + bonus3);
  if (bonus) {
    console.log("inside if statement: " + bonus);
    var numbers = [1, 5, 8, 2];
    var i = 0;
    while (i < numbers.length) {
      // 1. create new variable inside while loop
      var bonus3 = 30;
      console.log(bonus);
      i++;
    }
  }
}

The result is undefined once again since we are trying to access a nested variable from an outer scope.