CodeinWP CodeinWP

A Consideration of Variable and Function Scope in JavaScript

A Consideration of JavaScript ScopeMany aspects of JavaScript code development are taken for granted, and scope is really no different. Of course, in many cases where minimal code is required, variable scope (or function scope) is a non-issue. But if you’re planning to get into larger application development with JavaScript, then you need to understand at least the basics on scope in JavaScript.

Using some simple code examples, I’m going to run through the basics of scope and try to give beginning to intermediate JavaScript developers a better grasp of this very important concept.

Execution Context

JavaScript programs have what is referred to as the execution context of a variable or function, which defines exactly what data the function or variable has access to. Here is a simple example to illustrate two different contexts in one JavaScript program:

var sport = "baseball";
var player = null;

function getPlayer() {
  if (sport === "baseball") {
    player = "Evan Longoria"; // (the baseball player)
  } else {
    player = "Eva Longoria"; // (the actress)
  }
  var player2 = "Derek Jeter";
  return player;
}

getPlayer();

alert(player2);

In the above code, we’re declaring two variables, sport and player. Both variables are accessible inside the getPlayer function, since they reside in the global context. Therefore, based on the sport variable’s value, we can determine a new value for the player variable.

But, since the function is, in itself, a different context, the variable player2 is only accessible inside the function, and not in the global context. So, this script runs fine up until the last line, which produces an error because the global context does not recognize the existence of player2.

Demo 1 – Demonstrating Two Different Contexts

What Exactly is the Global Context?

The global context of every JavaScript program coded for the browser is the window. This can be demonstrated with some changes to the code we just wrote. We’ll omit the last line, and instead execute the getPlayer function as a method on the window object. We’ll also “return” the value of player and wrap an alert around the function call, to see the return value. After that, we’ll alert the player variable as a property of the window object. Here is the code:

var sport = "baseball";
var player = null;

function getPlayer() {
  if (sport === "baseball") {
    player = "Evan Longoria";
  } else {
    player = "Eva Longoria";
  }
  var player2 = "Derek Jeter";
  return player;
}

alert(window.getPlayer());
alert(window.player);

So if we omit the reference to the window object, the code will run exactly the same way, because all code that is not inside a function is in the global context, therefore belonging to the window object. Here’s a demo page:

Demo 2 – Demonstrating that the Global Context is the Window object

Nested Functions Have Their Own Context

As you’ve probably figured out, we could nest functions inside of our getPlayer function, and each of those nested functions would behave under the same principles we’ve already discussed. Let’s modify our code to demonstrate this:

var sport = "baseball";
var player = null;

function getPlayer() {
  if (sport === "baseball") {
    player = "Evan Longoria";
  } else {
    player = "Eva Longoria";
  }
  
  function getPlayer2() {
    if (player === "Evan Longoria") {
      player2 = "Derek Jeter";
    } else {
      player2 = "Teri Hatcher";
    }
    return player2;
  }
  return getPlayer2();
}

alert(getPlayer());
alert(getPlayer2());

It’s a little complex at first, but the above code is a good demonstration of how nested functions affect scope. First, as done previously, we declare the sport and player variables. Inside the getPlayer function we decide the value of player. Then we have the new getPlayer2 function, nested inside getPlayer. This nested function determines the value of player2 based on the value of player. Finally, the value of player2 is returned. So, when getPlayer is called in the alert, we can see the current value of player2.

Here is a demo page:

Demo 3 – Demonstrating Three Different Contexts

But this code produces an error when it gets to the last line. The last line tries to execute the getPlayer2 function in the global context, but this doesn’t work because the getPlayer2 function is not in the global context. Let’s try to alert the getPlayer2 function right before the return statement in the getPlayer function:

var sport = "baseball";
var player = null;

function getPlayer() {
  if (sport === "baseball") {
    player = "Evan Longoria";
  } else {
    player = "Eva Longoria";
  }
  
  function getPlayer2() {
    if (player === "Evan Longoria") {
      player2 = "Derek Jeter";
    } else {
      player2 = "Teri Hatcher";
    }
    return player2;
  }
  alert(getPlayer2());
  return getPlayer2();
}

alert(getPlayer());
alert(getPlayer2());

The above code will alert the value of player2 twice, then produce the same error as in the previous code. The first alert works because the getPlayer2 function is available inside the getPlayer function context, but not in the global context.

Here is a demo page, with the new alert message added:

Demo 4 – Demonstrating Three Different Contexts

Details to Take Note of in our Example

Here are some simple facts specifically associated with the above example code, to help you understand what is and isn’t accessible in the 3 different contexts:

  • The player variable is accessible in all 3 contexts (the global, plus both functions), because it is declared in the global context
  • The getPlayer2 function is not accessible in the global context because it is declared inside the getPlayer function
  • The getPlayer2 function is accessible inside the getPlayer function
  • The player2 variable is only accessible inside the getPlayer2 function, therefore is not available in the global context or in the getPlayer function

Summary

To summarize, every JavaScript program has at least one execution context (the window object), and every function inside that context will add yet another, separate, execution context. Also, all nested contexts will have access to their container contexts, which is somewhat similar to how the CSS Cascade works — although that’s kind of like comparing apples to oranges. Finally, the global context only has access to variables and functions declared inside the global context. And the same would be true for other “parent” contexts that have “child” contexts — they only have access to variables and functions in their own context and above.

I think variable and function scope in JavaScript is fairly intuitive and easy to grasp once you get your hands dirty and immerse yourself in it. There’s much more I could discuss on this topic, but I think that’s enough for the purposes of this post. Feel free to offer comments on anything you feel is important to consider with regards to scope in JavaScript.

3 Responses

  1. Jakub says:

    The examples should be more well thought.
    # if (sport === “baseball”) {
    # player = “Evan Longoria”;
    # } else {
    # player = “Eva Longoria”;
    # }

    I know it’s a demonstration code but it’s still better if a demonstration code makes sense. Posting examples like if (true) then return true; else return true. Is just bad coding.

  2. @Jakub:

    “Evan Longoria” is an American male baseball player. “Eva Longoria” (notice the N missing), is a female actress. They are two different people. I guess the subtle difference tends to look like an error to those not familiar with U.S. pop culture! :o)

  3. cb says:

    I was just having a JS scope discussion recently and I think these were the 3 main points I used:

    Functions have scope – a variable declared within a function is not accessible outside that function (vars in a function are “private”)

    A variable defined within a function is accessible to its nested functions.

    JavaScript is lexically scoped – functions run in the scope they are defined in, rather than the scope they are executed in.

Leave a Reply

Comment Rules: Please use a real name or alias. Keywords are not allowed in the "name" field and deep URLs are not allowed in the "Website" field. If you use keywords or deep URLs, your comment or URL will be removed. No foul language, please. Thank you for cooperating.

Markdown in use! Use `backticks` for inline code snippets and triple backticks at start and end for code blocks. You can also indent a code block four spaces. And no need to escape HTML, just type it correctly but make sure it's inside code delimeters (backticks or triple backticks).