Scoping Variables

Scoping Variables

Not only can variables in JavaScript be used to refer to any type of object at any time, they can actually be used without being declared at all! This can be a source of problems that are hard to identify because it will not be considered an error if you mistype a variable name. Rather, JavaScript will just assume you’re introducing a new variable. A variable’s scope is the context of code where that variable can be accessed. Whenever a variable is defined, it is assigned a scope for access based on where it is in the code. It is will be available to all inner scopes; loops, function calls, and further nested control structures. Basically, it will be available from the point it’s first defined until the scope in which it was defined exits. A variable is never available at a higher scope. If you declare a variable for use within function X, for example, that variable and its value are not available to the caller but are available to any functions that X calls. In fact, the variable is available to any functions called by functions that X calls. This means there’s no concept of local variables that aren’t visible outside your function (only those you call, and the functions they call can see them).

JavaScript will allow you to use a variable without declaring it (where it will be implicitly declared), but it changes the scope for that variable from what you would typically expect. An undeclared variable is automatically assigned global scope. In many cases, this is not a problem. A variable used within a function may not be accessed from a containing scope, so no other code is affected. Some variable names may be reused, however. And without requiring explicit declaration, the outside scope can be affected unintentionally. This can result in problems that are hard to debug, since they depend on the scope in which variables are used in addition to where the problem occurs.

In Listing 3-9 (from scoping.htm), two values are assigned to variables, one of which is defined and one of which is not. The same thing is done inside a nested function call. The function is able to modify both the declared and undeclared variables from the parent scope. When the function returns, the caller is now able to use the variable that was used without declaration inside the function. The other variable is scoped to the function and is no longer available after the function returns.

Listing 3-9
Image from book

<script type="text/javascript">

//use of a global variable without declaration
someUndeclaredVariable = "some undeclared variable";

//global variable declaration
var someDeclaredVariable = "some declared variable";

function someFunction() {
    //variable declared local to the function
    var nestedDeclared = "a nested declared variable";

    //undeclared variable used in function becomes global in scope
    nestedUndeclared = "a nested undeclared variable";

    //update the global variables
    someUndeclaredVariable = "modified undeclared variable";
    someDeclaredVariable = "modified declared variable";
}

someFunction();


//check the existence and values of the variables
if(!!someUndeclaredVariable) {
    document.write("someUndeclaredVariable = " + someUndeclaredVariable + "<br 
/>");
}

if(!!someDeclaredVariable) {
    document.write("someDeclaredVariable = " + someDeclaredVariable + "<br />");
}

if(!!nestedUndeclared) {
    document.write("nestedUndeclared = " + nestedUndeclared + "<br />");
}

if(!!nestedDeclared) {
    document.write("nestedDeclared =" + nestedDeclared + "<br />");
}


</script>
Image from book

Figure 3-1 shows the output of running the page from within both Internet Explorer and Firefox. Although there are attempts to access and write each of the four variables, only the two used in the global scope and the one used in a nested scope without declaration are available. The undeclared variables are automatically elevated to a global scope. The declared variable is limited to the scope in which it is defined. In a simple example like this, it appears straightforward, but in real-world, complex development tasks, the scoping of undefined variables can easily lead to problems that are hard to isolate and fix.

Image from book
Figure 3-1

In Figure 3-1, notice the small yellow exclamation point icon in the lower-left corner of Internet Explorer. When it is double-clicked, a dialog will appear that explains that there is a script error on the page. In fact, you can instruct Internet Explorer to treat this as an error and instead of getting an exclamation point in the corner, you will get a dialog box alerting you to the use of the undeclared variable. The details view says that script is attempting to use an undeclared variable. In Firefox, the Tools menu has an option for launching a JavaScript console for working with script on the page. The console will show additional warnings when running in strict mode. To access the configuration settings, enter about:config in the address bar. A long list of available configuration settings will appear. Any setting that has been changed from the default value will be in bold text, while the rest are in regular text. Scroll down until you see javascript.options.script and double-click the line. That will toggle the value to true from its default of false. Use of undeclared variables will then be flagged in the JavaScript console as a warning. The browser window itself won’t show an error, but the JavaScript console will show the warning when it is made visible by selecting it in the Tools menu. Internet Explorer and Firefox both provide ways to find the use of undeclared variables because of the problems that arise when coding that way. Always declare variables to limit their scope and avoid modifying data unintentionally. Figure 3-2 shows the configuration screen for Mozilla Firefox and the JavaScript console, with a warning visible for using an undeclared variable.

Image from book
Figure 3-2

Sometimes you want to test to see if a variable is in scope without causing an error. This can be done by testing for it as a member of the window class. If an object exists, it will be coerced to true in a Boolean test; if false, it doesn’t exist:


if(window.nestedDeclared) {
    document.write("nestedDeclared =" + nestedDeclared + "<br />");
} else {
  document.write("nestedDeclared is not in scope");
}