This is the first in a series of posts to provide C# and VB coders with a quick look at JavaScript. In this installment, I’ll look at JavaScript’s dynamic typing and its interesting (ie, not what you’d expect!) variable scoping
When ASP.NET debuted one of the improvements it brought to Web development was the way in which it hid away lots of painful, aggravating JavaScript. For a long time we thought that was a virtue. None of us liked JavaScript back then. It was fiddly, hard-to-debug, and required black magic incantations to work correctly.
Then along comes Ajax and does for JavaScript what the Eagles did for Joe Walsh. The promise of rich (or at least richer) user interfaces was quite alluring and that and better JavaScript-centric tools and books quickly made us reconsider JavaScript. While JavaScript still has warts and hairs, its singular role as the ubiquitous browser programming language trumps those problems. JavaScript is clearly with us for the long haul.
As ubiquitous as JavaScript is, I often bump into very bright VB and C# coders who don’t know much about JavaScript. This is the first is a series of articles that explains JavaScript for VB and C# programmers. I’m not going to try to provide the definitive JavaScript tutorial; the Internet doesn’t need another one of those. There tons of great JavaScript resources available (see the reference links at the end of this post). What I am going to present in this series a few JavaScript basics that have helped me. I’ll also introduce you to some JavaScript tools and techniques that work well for me.
Elusive language
For a VB or C# coder, JavaScript is a sneaky, elusive language. Syntactically, it grows from the same curly-brace, semi-coloned roots that C#, C, and even Java does. However, to master JavaScript you quickly need to learn that JavaScript is very much a different language than either C# or VB. The differences are subtle because JavaScript, especially the JavaScript written by rookie JavaScript coders, can indeed behave very much like imperative C# or VB. But, as we’ll see, behind the JavaScript curtain lurks some functional aspects that are very powerful, but easy to overlook. We’ll get to those later; let’s first focus on a few basics.
For the purposes of these posts, I’m going to assume at least a passing syntactical knowledge of C#. If you’re a VB coder with minimal or no C# knowledge, the examples I’ll provide here should be short enough that you’ll be able to intuitively grok the syntax.
Dynamic typing
Let’s start first with a simple JavaScript example. Figure 1 below shows a simple JavaScript function that apparently returns the sum of two numeric values. And indeed it does if both arguments passed to it are numeric values. With this code, you can quickly see the initial syntactical similarity that JavaScript has to C# and Java.
Figure 1. A simple JavaScript example
1var z = sum( 4, 8 );
2
3function sum( value1, value2 )
4{
5 return value1 + value2;
6}
However, unlike VB and C#, JavaScript is dynamically typed. As such, notice that in the code in Figure 1 JavaScript types aren’t explicitly declared for any variables or functions. Neither z, nor value1, value2 nor even the type that is returned by sum() are, or can be, declared. Note that .NET 3.5’s C# and VB’s var keyword, despite its looks, does statically type a variable. JavaScript is doing no such thing with its var. JavaScript’s var is truly dynamically. Given JavaScript’s dynamic typing, z can be a numeric value but then later be a string, as shown below in Figure 2:
Figure 2. JavaScript is dynamically typed
1 z = sum( 4, 8 );
2
3 z = “Neil”
Give this dynamic typing, it’s possible to call sum() with arguments of types other than numeric as shown below in Figure 3:
Figure 3. Sum()’s arguments aren’t explicitly typed
1var z = sum( “Neil”, “Young” );
The call in Figure 3 returns the concatenated result “NeilYoung.” JavaScript would even let you call sum() as shown below in Figure 4:
Figure 4. Dynamic typing in action again
1var z = sum( “Neil”, 8 );
where the result would be “Neil8.” Interesting, huh? JavaScript has the innate ability to dynamically coerce types when necessary. In the case of Figure 4 above, the numeric value 8 is coerced to string to produce the concatenated string result. But wait, it gets more interesting. Guess the result of Figure 5 below:
Figure 5. Dynamic typing in action
That’s right, it’s “68.” Now, guess the result of Figure 6 below; it’s a little trickier:
Figure 6. Attempting explicit casting
1var z = sum( 0 + “6”, 8 );
In this case, the result is “068.” As I was learning this, I would have bet you a paycheck that the 0 + “6” would have resulted in a coerced numeric value of 6, but that isn’t the case. Like VB and C#, the + sign means either arithmetic addition or string concatenation. If there is a string somewhere in the expression, JavaScript always assumes the + sign means string concentration. Getting sneakier, consider the output of Figure 5 below:
Figure 7. A way to explicitly cast a string to numeric value
1var z = sum( 1 * “6”, 8 );
In this case, because the * sign has only one meaning, arithmetic multiplication, the 1 * “6” does indeed get coerced to the numeric value 6 and the result of calling sum() as shown in Figure 7 is the numeric value 14. If you try an arithmetic operation against the wrong type (eg, 1 * “A”) then JavaScript returns a special value named “NaN” indicating that the operation couldn’t be performed on non-numeric values. I’ll discuss NaN later in a post about JavaScript error handling.
We’ll see later that JavaScript has a few other explicit type conversion options available to it. We’ll also see that JavaScript has the ability to test the types of variables so that you can build in a little type-safe protection when it’s needed. Note though, the impact that JavaScript’s dynamic typing has on function naming. The name sum() for the function above (at least as it is currently written) is a poor name for that function because it can do more than just the numeric operation implied by the name “sum().”
Unusual variable scoping
Variable scoping in JavaScript has two levels to it: an easy, pretty obvious level and another richer but more complex level. This second level has to do with JavaScript closures. Closures are beyond the scope of this post, but will be covered in another later. For now let’s consider the basic implementation of JavaScript variable scoping.
When you declare a variable with JavaScript, the var keyword is optional (although is should be required!). For example, Figure 8 below declares variable x
Figure 8. Declaring a variable with the var keyword
as does the line below in Figure 9:
Figure 9. Declaring a variable without the var keyword
Both lines declare a variable x, but there is a difference. When you use var to declare a variable, that variable is scoped either globally to all functions (if it’s declared outside of any functions) or scoped to the function in which it’s declared. Let’s look at a few more examples.
Figure 10 below shows a global variable x being declared. Because x isn’t owned by a function, its value is available anywhere. Remember, too, that global Javascript variables are available to all other JavaScript files used by any one page. Global truly means global in this case.
The example below shows x being assigned to the scopeTest()’s variable y which, because the var keyword is used, is available only inside scopeTest().
Figure 10. Declaring a variable outside the bounds of functions
1var x = 89;
2
3function scopeTest()
4{
5 var y = x;
6}
Because x is global by virtual of not being declared inside a function, the use of var in line 1 in Figure 10 above is option. Had line 1 omitted the var keyword, the behavior in Figure 10 would not have changed. Having said that, the var keyword doesn’t change the global behavior (because x is declared outside the bounds of any functions); you should always use the var keyword.
If the code in Figure 10 were written as shown below in Figure 11, the variable y declared in scopeTest() is global (because it isn’t declared with the var keyword). The interesting thing about the y variable is that it isn’t available to the rest of the program until scopeTest() has been called once. Therefore, the code below will fail at line 3 (where writeLine() is a diagnostic function to display a variable we’ll discuss later) because testScope() hasn’t yet been called.
Figure 11. declaring a global variable in a function
1var x = 89;
2
3writeLine( y )
4
5function scopeTest()
6{
7 y = x;
8}
However, anytime after a call is made to testScope(), then the global variable y it declared is available to the rest of the JavaScript program. Figure 12 below will now correctly display the value of the global variable y.
Figure 12.Referencing y
1var x = 89;
2
3scopeTest();
4
5writeLine( y );
6
7function scopeTest()
8{
9 y = x;
10}
JavaScript variables are not block-scoped
Remember that variables are not blocked scoped in JavaScript like they are in C# or Java; rather in JavaScript variables declared in a function are scoped to all of the code in that function. Therefore, what appears as though it should be a variable private to the if block below is really available from where it’s declared on down in the function. Figure 12 below shows this.
Figure 12. JavaScript local variables are block-scoped
1function scopeTest()
2{
3 // Variable x is undefined here.
4 if ( condition )
5 {
6 // Variable x is available beyond the
7 // if block’s scope.
8 var x = 89;
9 }
10 // Variable x is available here!
11}
As you can imagine, bad things can happen when you omit the var keyword. The general rule of this is don’t ever omit it! If a variable needs to be global, don’t declare it inside a function, declare as an inline variable. Note also that the dynamic nature of JavaScript can get you in big trouble quickly if you aren’t vigilant. Consider the code below in Figure 13:
Figure 13. JavaScript doesn’t have Option Explicit!
1Function scopeTest()
2{
3 var myRate = 89;
4 Myrate = myRate + 100;
5}
In this case, I meant to increment the value of myRate by 100. However, I got the case wrong on line 2 spelling Myrate instead of myRate. So, without any fanfare, JavaScript sees that not as an error, but rather as my desire to declare a second global variable named Myrate. Not only was myRate not incremented as needed but I also got a free global variable out of the mistake. And, this is important, myRate has an incorrect value with JavaScript providing no clues as to anything being amiss.
For my money, the ease with which a coder can make such a simple, profound mistake is why JavaScript got a bad name in the first place. You must always be aware of case. If JavaScript had an option explicit-like setting like VB does (disallowing variable declarations without the var keyword), we’d be protected against such boneheaded, but certainly possible, errors.
While there isn’t anything built into JavaScript to help you avoid these errors, there is a superb online JavaScript utility called JSLint you can use to screen your code for such errors. JSLint investigates your JavaScript and reports lots of information about it. One of the things it reports is the sloppy use of variables as shown in Figure 13. For JavaScript work of any real merit, the use of JSLint is highly recommended.
The lesson learned: take great care with your JavaScript variable naming and watch your case.