Scope From Functions

The most common answer to those questions is that JavaScript has function-based scope. That is, each function you declare creates a bubble for itself, but no other structures create their own scope bubbles. As we’ll see in just a little bit, this is not quite true.

But first, let’s explore function scope and its implications.

Consider this code:

  1. function foo(a) {
  2. var b = 2;
  3. // some code
  4. function bar() {
  5. // ...
  6. }
  7. // more code
  8. var c = 3;
  9. }

In this snippet, the scope bubble for foo(..) includes identifiers a, b, c and bar. It doesn’t matter where in the scope a declaration appears, the variable or function belongs to the containing scope bubble, regardless. We’ll explore how exactly that works in the next chapter.

bar(..) has its own scope bubble. So does the global scope, which has just one identifier attached to it: foo.

Because a, b, c, and bar all belong to the scope bubble of foo(..), they are not accessible outside of foo(..). That is, the following code would all result in ReferenceError errors, as the identifiers are not available to the global scope:

  1. bar(); // fails
  2. console.log( a, b, c ); // all 3 fail

However, all these identifiers (a, b, c, foo, and bar) are accessible inside of foo(..), and indeed also available inside of bar(..) (assuming there are no shadow identifier declarations inside bar(..)).

Function scope encourages the idea that all variables belong to the function, and can be used and reused throughout the entirety of the function (and indeed, accessible even to nested scopes). This design approach can be quite useful, and certainly can make full use of the “dynamic” nature of JavaScript variables to take on values of different types as needed.

On the other hand, if you don’t take careful precautions, variables existing across the entirety of a scope can lead to some unexpected pitfalls.