JavaScript for the C# Developer Part 2 – Variables and Scoping Rules

Next: JavaScript for the C# Developer Part 3 – Functions

If you are reading this post I probably don’t need to tell you what a variable is, but the chances are good that you misuse variables in JavaScript because as you learned in the first lesson, JavaScript is not C#!

Implied Global Variables

In JavaScript variables are declared using the optional var statement. The var statement declares a variable and optionally assigns a value. If you forget to declare a variable and simply use it, JavaScript will happily allow you to do so and will create a global variable as a result!

This behavior would be dangerous in any language, but it is especially dangerous in JavaScript because of <script> elements. Generally speaking, you have no way of knowing which other scripts might be used with your script when you are programming. This means that global variables are inherently dangerous. There is nothing to ensure that another script doesn’t make the same mistake and create accidental global variables. Two scripts using the same global variable name can easily collide and create interesting bugs.

Consider the script found here: which illustrates the issue.

In this sample I have a script block that uses the variable I which is treated as a number. Elsewhere I also use a variable named I to which a string is assigned. Clicking the button yields:

It does so because I is not a number, NaN. In this example it is easy to see why this is so. In real life this type of defect can cause unpredictable behavior when scripts collide and can be very difficult to find! Another form of this problem is when you simply mistype a variable. If you transpose some characters JavaScript will happily make a new variable for you on the fly of global scope instead of producing a runtime error or warning.

Generally speaking JSLint will catch this problem and warn you that you have created an implied global variable.

C# has Block Scope, JavaScript does not!

Consider the following C# code:

This code results in a compile time error because C# has block scope and the code tries to use I outside of the block in which it is declared (the for block).

Similar code in JavaScript works.

Even though i was declared in the for block, it exists and is accessible even after the for block completes.

JavaScript doesn’t have block scope, it has function scope. Parameters and variables defined in a function are not visible outside the function, but a variable defined in a function is visible anywhere within the function. A function acts as a container and functions can contain other functions (more on that in another lesson). The key point is that a function can see the variables defined by its parent and other ancestors. These variables are ‘up-visible’ but because variables defined in a function outside the function, variables are not ‘down-visible’. This concept is easy to understand with this sample:

Within the function inner() the variable input is visible because it is defined by its ancestor function top(). However innerVar is not visible from top() nor is top()’s named argument input visible outside the function top(). In both cases the test for undefined returns true because those variables are undefined at that scope.

Global variables are an Illusion

The fact that functions can see up implies that there must be an outer container that holds everything. This container’s name is window and it is not a function but an object. The window object provides the runtime context and contains properties that let you access things like the document and location as well as methods like alert and events like onload. Therefore, creating an implied global variable by forgetting var is the same operation as adding a member to window.

Global variables are just like local variables but they are local to window and thus visible everywhere to all of the functions contained by the window.

The Most Common Scope Related Error

Thus far you’ve seen two ways to create members on the window object, accidently by forgetting var and deliberately by using window. There is another far more common way that developers can create global variables and unintended name collisions.

Consider a page like this:

Where script.js is as follows:

Both the page and the script use variables named x and y and both use the var keyword. The browser reads and executes script.js first because it is at the top of the page. The script block at the bottom of the page executes last. When it executes the function foo() the output is not 4 but is abcd. This is because whenever you declare a variable that is not contained by a function it is attached to window!

This is easily the most common and dangerous issue with JavaScript code we encounter at our customers. The next post will cover functions and how we can use them to protect our variables.

Next: JavaScript for the C# Developer Part 3 – Functions


Author: Doug Ware

Author: Doug Ware