Section 2.2. Scope


2.2. Scope

The next critical characteristic of a variable is its scope: whether it's local to a specific function or global to the entire JavaScript application. A variable with local scope is one that's defined, initialized, and used within a function; when the function terminates, the variable ceases to exist. A global variable, on the other hand, can be accessed anywhere within any JavaScript contained within a web pagewhether the JS is embedded directly in the page or imported through a JavaScript library.

In Chapter 1, I mentioned that there is no special syntax necessary to specifically define a variable. A variable can be both created and instantiated in the same line of code, and it need not look any different from a typical assignment statement:

num_value = 3.5;

This is a better approach:

var num_value = 3.5;

The difference between the two is the use of the var keyword.

Though not required, explicitly defining a variable using the var keyword is strongly recommended; doing so with local variables helps prevent collision between local and global variables of the same name. If a variable is explicitly defined in a function, its scope is restricted to the function, and any reference to that variable within the function is understood by both developer and JavaScript engine to be that local variable. With the growing popularity of larger, more complex JS libraries, using var prevents the unexpected side effects created by using what you think is a local variable, only to find out it's global in scope.

To illustrate this type of side effect and the importance of explicitly declaring variables, Example 2-1 demonstrates a web page with separate blocks of JavaScript, each accessing the same variable, message. The page includes two external JavaScript files, both of which also set the same variable: one, globally, outside the function that uses it; the other, locally, within the function. None of the examples use the var keyword to expressly define the variable.

Example 2-1. The dangers of global variables and not declaring local variables explicitly

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html> <head> <title>Scope</title> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <script type="text/javascript" src="/books/4/327/1/html/2/global.js" > </script> <script type="text/javascript" src="/books/4/327/1/html/2/global2.js"> </script> <script type="text/javascript"> message = "I'm in the page"; function testScope(  ) {   message += " called in testScope(  )";   alert(message); } </script> </head> <body onload="testScope();global2Print(  );globalPrint(  )"> <script type="text/javascript"> message += " embedded in page"; document.writeln(message); </script> </body> </html>

When the page initially loads, the JS in the head element is processed first, and the message variable is set to a string with the words, I'm in the page. The variable is then output to a dialog window from a function, testScope, which is called when the page finishes loading. Before printing the message, though, the function also concatenates (adds to the end) the string, called in testScope( ) to the original text. Later in the web page, another block of JavaScript also accesses message and concatenates its own text to the message string: embedded in page. The modified string is then printed out to the web page.

The page also imports two JavaScript external files. The first, global.js, concatenates its own string, globally in globalPrint, to the message. The source file also has a function, globalPrint, which opens a dialog and publishes the message:

message += " globally in globalPrint"; function globalPrint(  ) {   alert(message); }

The last component of this application, the JavaScript source file global2.js, has a function, global2Print, and also modifies message, this time by adding "also accessed in global2Print":

function global2Print(  ) { message += " also accessed in global2Print"; alert(message); }

When the web page is first opened, message is initially set in the first script block, and then modified and printed out in the second script block as the page loads. The message at this point is:

I'm in the page embedded in the page

Nothing too surprising here. Via the onload event in the body tag, testScope is called as soon as the page is loaded. This function modifies the message string, and pops up a window with:

I'm in the page embedded in the page called in testScope(  )

Clicking the OK button closes the window, and the next function listed in onload is called: global2Print in global2.js. This function adds "Hi, you were here", resulting in a dialog with the following:

I'm in a page embedded in page called in testScope(  ) also accessed in global2Print

The message is getting long and has been modified in multiple JS blocks across two files, but it's not finished yet. The last function called from the onload event is globalPrint in global.js. The JavaScript in this file modifies the string message, and globalPrint outputs it via an alert. The resulting text is:

I'm in a page embedded in a page called in testScope(  ) also accessed in global2Print

Now, this is when what's happening with message may begin to get confusing. As you can see, the message didn't change between calling the function in global2.js and calling the function in global.js, but JavaScript in both files modified the string.

The discrepancy in the result is that global2.js modified the string directly within the function before printing, treating it as a local variable, while global.js modified it outside the function, treating it as if it were global. When the JavaScript source file is loaded, the JavaScript is processed as the page is loaded, and the message set globally is lost as soon as the JavaScript in the head element of the web page body is processed. This script block treats message as a local variable and sets, rather than modifies, the message variable's contentsoverwriting the value set in the global variable of the same name.

After a few more directs and redirects, and mixing global and local access of a variable with nothing to differentiate the two, you'll be surprised at the result at some point no matter how carefully you follow the variable. Guaranteed.

Though not demonstrated, a variable declared within a code block (delimited with curly braces) has scope beyond the block. It's accessible by the code for the entire function, or a script if the block is not within a function. JavaScript 1.7 adds block-level scoping, but this language version is not universally implemented in browsers at this time.


What's the moral of all of this, then? Well, there are two, really.

The first is to be especially careful when using global variables. Some would say that with JavaScript's ability to create objects and attach properties, as well as pass values as function parameters, you shouldn't use global variables. However, global variables can be very handy: they can keep running counts or hold timers, or any value necessary to more than one function.

Still, if you use large JavaScript libraries, no matter how careful you are, a global variable of the same name as the one you're using in your library can happen. When it does, you're going to get unexpected side effects.

An additional reason to avoid global variables is that they add to the overall memory burden of a JS application. Memory management for JavaScript is managed for us, but we can help the process. Unlike local variables, which are freed when the function ends, global variables hang around until the web page, and JS application, are no longer loaded in the browser.


If using extreme caution with global variables is one of the morals learned in this section, what's the second? It's this: always explicitly define a local variable using the var keyword. If you don't, it's treated as a global variablepure and simple.

JavaScript Best Practice: Use the var keyword to define any variable regardless of scope: global or local. As the old saying goes, begin as you mean to continue. This is particularly true when you are learning JavaScript.


Widgets for JavaScript

After a long hard day of working with variable scope, I like to spend a little time playing around with what I call "geegaws"fun utilities, toys, what have you, that can be installed quickly and are intuitively simple and easy to use.

I have both a Mac and a Windows notebook computer, and I like both, though I prefer my Mac. One of the items I especially like about my Mac is the number of widgets I can install into my Dashboardthe widget space that can overlay your contents. It's a wonderful spot for geegaws, including JavaScript geegaws.

Among the geegaws I have currently installed on my Mac are: HTML Test 2, which can be used to test JavaScript; ExecScript 2.0, which can run JS typed into a window; Regex, the regular expression survival kit; and Rob Rohan, a JavaScript shell.

Most JavaScript widgets can be found in the Developer category of the widget download site: http://www.apple.com/downloads/dashboard/developer/. Each is installable with just one click of a button, with a minimum of footprint (resource use).





Learning JavaScript
Learning JavaScript, 2nd Edition
ISBN: 0596521871
EAN: 2147483647
Year: 2006
Pages: 151

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net