Chapter 6. Scope

In the Try It section of Lesson 5, you used a variable called i to count a for loop's iterations. Most programmers use the i identifier for that exact reason; it's used everywhere and all the time to count loop iterations. So if multiple developers were working on different pieces of the same application, wouldn't all these uses of i conflict with each other?

Thanks to scope, the answer is no. Scope is an important concept in programming, particularly in JavaScript. It's important to understand scope because it determines what variables a function can see and access.

GLOBAL SCOPE

Variables and functions defined outside of a function are created in the global scope. JavaScript's global scope is the topmost level of scope. It persists throughout the entire web page, and any variables and functions created in the global scope are accessible anywhere in the page.

Consider the following code:

var globalVar = "This is a global variable.";

function globalFunction() {
    globalVar = "This changes the value of globalVar";
}

globalFunction();

In this example, a variable called globalVar is created outside of any function; thus, it is a global variable and can be accessed anywhere in the page. Because the globalVar variable is a global variable, the globalFunction() function, which is also defined in the global scope, can access the variable and modify it. Since globalVar is global, its new value can be seen and accessed anywhere in the page; modifying a global variable's value makes the new value visible and usable everywhere.

Global variables and functions persist throughout the page, and they remain relevant to the page until the user navigates to a different one. Contrast that with functional scope, in which scope is limited only to the function.

FUNCTIONAL SCOPE

Think of scope as shown in Figure 6-1.

Figure 6-1

Figure 6.1. Figure 6-1

The shaded area outside the circles is the global scope. All variables and functions defined in this area have access to the other variables and functions in the same space. The circles represent functions: Some are globally defined while others are defined inside other functions. The boundary line of each circle is a barrier preventing access to the variables and functions defined within the circle from items outside the circle. However, a circle is contained within either another circle or the global space, and the items defined within a circle have complete access to the items defined outside the circle.

This figure shows the primary characteristic of scope in JavaScript. Items in a particular circle of scope have access to the items inside their containing circle, as well as items outside the circle. They cannot, however, penetrate the boundary into another circle — even one contained within itself.

The variables and functions defined within a function are said to have functional, or local, scope — they are local to their containing functions. They have access to global variables and functions, as well as to other variables and functions defined within the same function, but they cannot be accessed from outside the function in which they are defined. This can be shown in the following example:

var globalVar = "This is a global variable.";

function globalFunction() {
var localVar = "This is a local variable";
    globalVar = localVar;
}

globalFunction();

alert(localVar); // error; execution stops
alert(globalVar); // "This is a local variable";

This example uses the global variable and function from the previous section, but adds a variable initialization within the function. This new variable is called localVar, a local variable to the globalFunction() function.

The second-to-last line of this example uses an alert window to display the value contained within localVar. The only problem here is that localVar cannot be accessed outside of the globalFunction() function because it is a local variable of that function — it is only accessible to code within the function. What this line actually does is try to find a global variable called localVar. Since it doesn't exist, an error occurs and code execution stops. Neither alert window displays.

When the function exits, all its local variables are destroyed. But notice that within the function, the globalVar variable was changed to contain the value contained within localVar. While the local variable localVar was destroyed, its value was copied to globalVar before the function exited.

The same behavior is seen with function parameters. The function sees them as local variables, and while all code within the context of the function can access those parameters, code outside the function cannot. Look at the following example:

var globalVar;

function globalFunction(paramOne) {
    globalVar = paramOne;
}

globalFunction("This is a parameter");

alert(paramOne); // error; execution stops
alert(globalVar); // "This is a parameter"

This code recreates the globalFunction() function by modifying it to accept a parameter. After the function declaration is the statement to execute globalFunction() by passing a string value to the function. The next-to-last line attempts to access a variable called paramOne, but such a variable does not exist within the global scope. So once again, an error occurs and code execution stops before an alert window pops up.

Let's make things a little more interesting. Look at the following code:

var globalVar = "This is a global variable";

function globalFunction(paramOne) {
    var localVar = "This is a local variable";

    function innerFunction() {
var innerVar = "This is an inner function's variable";
        alert(globalVar);
        alert(paramOne);
        alert(localVar);
    }

    innerFunction();
    alert(innerVar); // error; execution stops
}

globalFunction("This is a parameter");

// code execution never gets here, but if it did...
innerFunction(); // error

This code yet again recreates the globalFunction() function. It accepts a parameter as in the previous example, but the body has drastically changed. A function called innerFunction() is declared inside globalFunction()'s body. This function is created within the scope of globalFunction(), so it has access to all other variables and functions within globalFunction(), as well as those within the global scope. In other words, it can directly access the paramOne and localVar variables of the outer globalFunction() function and the globalVar variable in the global context.

The innerFunction() function has its own local scope. While it can access the items in the outer function and global scopes, the outer scopes cannot access the innerVar variable defined within innerFunction(). Also, the innerFunction() function cannot be accessed outside of globalFunction().

NO BLOCK-LEVEL SCOPES

The idea of scope can be confusing, especially when you're dealing with functions within a function within a function. Many other languages include a level of scope for every block of code — that is, a list of statements inside a pair of curly braces ({}). This means that if statements, loops, and switch statements have their own level of scope in other languages. This is not the case with JavaScript. Consider the following code:

if (true) {
    var hundred = 100;
}

alert(hundred);

In other languages the hundred variable would be destroyed after the if statement was executed, and so the last line would result in an error. JavaScript, on the other hand, adds the declared variable to the scope in which it was created (the global scope in this case, making it usable anywhere in the application).

The function code block is one of the few code blocks with its own scope. Most other code blocks, such as if ... else, loops, and switches, share the same scope as their container.

VARIABLE DECLARATIONS

Throughout this book, variable declarations and initializations have started with the var keyword. It is, in fact, possible to create a variable without using the var keyword, but doing so has the side effect of creating a global variable. Look at the following example:

function someFunction() {
    someVariable = "This creates a global variable";
}
someFunction();
alert(someVariable);

This code creates a function called someFunction(). Its only statement assigns a string value to a variable called someVariable. When this statement executes, the JavaScript engine looks for the someVariable variable to assign it a new value. The engine can't find it, and so creates it in the global scope. When the last line of this code executes, it displays the text "This creates a global variable".

Even though this may seem beneficial, omitting the var keyword can lead to unexpected errors. It is strongly recommended that you always use a var keyword to declare variables.

This behavior is caused, in part, by how JavaScript looks up identifiers.

IDENTIFIER LOOKUP

When you access a variable or a function in your code, the JavaScript engine begins to look up the item's identifier, starting in the current level of scope. If it cannot find a match in scope, it begins to look in the next level of scope — traveling up to every level of scope until it either finds a match or doesn't find one in the global scope. For example, consider the following code:

Figure 6-2

Figure 6.2. Figure 6-2

var globalVar = "Hello, Global Scope!";

function someFunction() {
    alert(globalVar);
}

This code creates a global variable called globalVar and the someFunction() function to alert globalVar's value. When someFunction() executes, the JavaScript engine goes through a process to find the globalVar identifier starting at the bottom of Figure 6-2.

Because identifiers are looked up in this way, it's possible to override a variable or function defined in a higher level of scope with one in the local scope. Look at this example:

var aNumber = 100;

function overrideVar() {
var aNumber = 101;
    alert(aNumber); // 101
}

overrideVar();
alert(aNumber); // 100

This code creates a global variable called aNumber; it has a value of 100. Next the code creates a function called overrideVar(). Inside this function, another variable called aNumber is initialized with a value of 101. The second line of the function uses the aNumber variable by passing it to the alert() function. JavaScript performs a lookup for the aNumber identifier, finds one in the current scope, and immediately stops searching for the identifier. Therefore the local aNumber variable is used in the call to alert(), so the alert window displays 101.

The local aNumber variable does not modify the global variable of the same name in any way, but any line of code inside overrideVar() uses the local aNumber variable instead of the global variable. The JavaScript engine simply finds the identifier in the local scope, and uses it because the engine found that variable's identifier first.

Outside the function, the global aNumber variable is intact. The aNumber variable inside the overrideVar() function is limited to the scope of that function, so the final line of code in this example calls the alert() function, passes the global aNumber variable, and displays the value 100 in the alert window.

TRY IT

In this lesson, you learn about JavaScript's scope and how it can affect your application. You will write a function to determine the area of triangles and rectangles.

Lesson Requirements

For this lesson, you need a text editor; any plain text editor will do. For Microsoft Windows users, Notepad is available by default on your system or you can download Microsoft's free Visual Web Developer Express (www.microsoft.com/express/web/) or Web Matrix (www.asp.net/webmatrix/). Mac OS X users can use TextMate, which comes as part of OS X, or they can download a trial for Coda (www.panic.com/coda/). Linux users can use the built-in VIM.

You also need a modern web browser. Choose any of the following:

  • Internet Explorer 8+

  • Google Chrome

  • Firefox 3.5+

  • Apple Safari 4+

  • Opera 10+

Create a subfolder called Lesson06 in the JS24Hour folder you created in Lesson 1. Store the files you create in this lesson in the Lesson06 folder.

Step-by-Step

  1. Open your text editor and type the following code:

    function shapeArea(base, height, shape) {
        var area = 0;
    
        function triangle() {
            area = (base * .5) * height;
        }
    
        function rectangle() {
            area = base * height;
        }
    
        switch (shape) {
            case "triangle":
                triangle();
                break;
    
            case "rectangle":
                rectangle();
                break;
    
            case "square":
                rectangle();
                break;
        }
    
        return area;
    }

    This code creates a function called shapeArea(). It accepts three arguments: a number representing the shape's base, a number representing the shape's height, and a string containing the type of shape of which to compute the area. Inside the function, a local variable named area is initialized with the value of 0.

    Next are two inner functions: triangle() and rectangle(). They access the values passed to the base and height parameters of shapeArea(). Because of local scope, they have access to those values.

    Then a switch statement switches through three possible values for the shape parameter: triangle, rectangle, and square. The appropriate inner function is called based on shape's value. Finally, area is returned to the caller.

  2. Save this file as lesson06_sample01.js.

  3. Open another instance of your text editor, type the following HTML, and save it as lesson06_sample1.htm.

    <html>
    <head>
    <title>Lesson 6: Example 1</title>
        <script type="text/javascript" src="lesson06_sample01.js"></script>
        <script type="text/javascript">
            var area = shapeArea(2, 2, "square");
            alert(area);
        </script>
    </head>
    <body>
    
    </body>
    </html>
  4. Open the HTML file in your browser. An alert window will display the value 4.

To get the sample code files, you can download Lesson 6 from the book's website at www.wrox.com.

Note

Please select Lesson 6 on the DVD to view the video that accompanies this lesson.

Step-by-Step
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.191.68.18