Scope

scope = all the variables and functions that are visible from a given location in your code

The two primary forms of scope are Global and Local

Globally scoped variables can be seen from anywhere in the program

Locally scoped variables can be seen only nearby where they are defined -- usually inside the same function or code block

Global Scope

If you declare a variable without a keyword (var, let, const) then it is a global variable and can be seen and used by any line of code in your entire program

Global variables are very useful but also very dangerous. A mistake in any part of your program using a global variable could introduce a bug in any other part of your program using that global variable.

(ES5 introduced strict mode which can reduce this risk -- though not eliminate it entirely)

Implicit vs. Explicit globals

Globals are usually bad, but they are good for when you want to call a particular function from literally anywhere in your code... for instance, when you want to tell your analytics server that something interesting just happened.

If you really want to use a global variable, you should do so explicitly, so other readers of your code will know that you did it intentionally.

JavaScript programs have a global object whose properties are available as global variables. In web browsers, the global object is named window; in NodeJS, the global object is named global.

// implicitly global
sendAnalytics = function(message) { ... }

// explicitly global (Browser)
window.sendAnalytics = function(message) { ... }

// explicitly global (NodeJS)
global.sendAnalytics = function(message) { ... }

Either of the above lines (in an HTML JS app) will allow any line in the entire rest of your program to call sendAnalytics('user clicked "unsubscribe" button')

Scope is a One-Way Mirror

scope is a one-way mirror -- inner scopes can see out, but outer scopes cannot see in

one way mirror functions

Mr. Bean -- in the interrogation room scope -- can't see the cops in the observation room scope.

Block Scope

let and const are block-scoped: any block of code surrounded by { curly braces } can have its own set of local let variables

let name = 'Mr. Bean';
{
    let name ='Detective Bob';
    {
        console.log(name);
    }
    console.log(name);
}
console.log(name);

If a variable name can't be found in the current scope, then JavaScript looks in the next outer scope, and so on

Exercise: Guess the Variable

let fruit = 'Apple';
{
    let fruit ='Blueberry';
    {
        let name = 'Cantaloupe';
    }
    console.log(name); // What is this fruit?
}

Top Level Functions are Global

A function defined with the term function at the left margin is hoisted, meaning it

let name = 'Alice';     // this name is global

let alpha = function() {
  console.log(name);    // alpha can see global var
  beta();               // alpha can see global function named beta
}

// alpha() uses let so must be called after it is defined
alpha();

function beta() {     // beta is hoisted!
  let name = 'Bob';     // this name is local to beta
  console.log(name);    // prints "Bob"
}

console.log(name);      // prints "Alice"

Parameters are local to their function

let opinion = 'i love cheese';
console.log(rant(opinion));

function rant(message) {
    let loudMessage = message.toUpperCase() + '!!';
    return loudMessage;
}

the above rant function has two locally scoped variables:

Exercise: Guess the Variable with Functions

let poet = 'Robert Frost';

function famousPoem(poet) {

  let poemAuthors = {
   'Robert Frost': 'Stopping by Woods on a Snowy Evening',
   'Walt Whitman': 'Leaves of Grass',
   'undefined': 'The Lanyard' // Billy Collins
  };
  return poemAuthors[poet];
}

famousPoem('Walt Whitman'); // Which Poem?
famousPoem(poet);           // Which Poem?

poet = 'Maya Angelou';
famousPoem();               // Which Poem?

Scope Error

function gamma() {
    let x = "declared inside gamma";
    console.log("Inside gamma: x is " + x);
}

console.log(x);  // ReferenceError: x is not defined

Closure Scope

JavaScript also supports lexical scope (aka "closure scope" or "nested scope") which means that variables defined above the current function may also be visible...

function sing() {               // outer function
  let numberOfBottles = 99

  function bottlesOfBeer() {    // inner function
      let message = '' + numberOfBottles
        + ' bottles of beer on the wall';
      return message;
  }

  while (numberOfBottles > 0) {
      console.log(bottlesOfBeer())
      numberOfBottles -= 1
  }

}

bottlesOfBeer is enclosed within sing, so it inherits sing's scope

numberOfBottles is visible inside both sing() and bottlesOfBeer()

Nested Scopes

Every time you call a function, JS creates a new scope

that scope points to the current scope

and so on recursively

(and -- strangely enough -- variables that are defined inside a nested function are still alive after that function returns (?!?!?!) -- more on this at the very end of this lesson)

Why Nested Scopes? 1

function countLetters(words) {
    let letterCount = 0;
    words.forEach(function(word) {
        letterCount += word.length;
    });
    return letterCount;
}

total is visible inside the inner (callback) function as well as the outer (countLetters), so forEach can behave like other loops

This doesn't work:

function addLetterCount(word) {
    letterCount += word.length;
}

function countLetters(words) {
    let letterCount = 0;
    words.forEach(addLetterCount);
    return letterCount;
}

...because addLetterCount is not nested inside countLetters

Why Nested Scopes? 2

function printGrid(grid, delimiter) {

    function printRow(row) {
        console.log(row.join(delimiter));
    }

    let i = 0;
    while (i < grid.length) {
        printRow(grid[i]);
        i = i + 1;
    }
}

this is a contrived example, but the idea is that

Why Nested Scopes? 3

let count = (function() {
    let value = 0;  // private variable
    let increment = function() {
        value = value + 1;
        return value;
    };
    return increment;
})();

count() // returns 1
count() // returns 2
count() // returns 3

value   // ReferenceError: value is not defined

 Previous Lesson Next Lesson 

Outline

[menu]

/