Simple JavaScript Concepts
LUG Programming Course, 21st January 2008
In this lesson we started to write some simple JavaScript. This was a little tedious for those with previous programming experience, but it served to highlight several important points of the JavaScript programming language.
Just as importantly, this lesson helped familiarise the students with the Firebug add-on.
I was a little too slow starting the lesson, wasting about 30 minutes, so I overran by about 20 minutes, and didn't manage to finish all the material. Fortunately, this first real programming lesson gave me some feedback, so that I can better pace the following lessons. I'm glad to say that I had at least prepared enough material, finishing 30 minutes early might have been embarrassing.
Programming in 60 Seconds
What is a computer program? The Columbia Electronic Encyclopedia offers this
definition: “A series of instructions that a computer can interpret and execute”. That's a pretty widely scoped statement, so let's think of an example. One task could be to count the number of vowels in the definition. There are 23 of them. The instructions required would include the data; a counter, the definition text, and a list of vowels. They would also include operations that manipulate the data; extract each character of the definition, check if it is a vowel, and increment the counter accordingly.
What would that look like in JavaScript?
var definition = "A series of instructions that a computer can interpret and execute";
var count = definition.match(/[aeiou]/ig).length;
Alright, I know that this is a bit cryptic, so I'll walk you through it. The first line is fairly simple; we create a named data element (definition) with the definition text. The text is a string, so I have to use quotes, otherwise the JavaScript interpreter would think it was something else.
The second line is cryptic. There are three data elements, of which one is named count. The second data element is a regular expression /[aeiou]/ig, and the third data element is the result of calling the definition.match() method, which is an array, for the curious. The array has a property length, which gives us our vowel count.
But, there's a But
Well, actually the above code doesn't always work. There is one specific input which causes an error. I'll show you how to find (and then correct) the error next week.
OK, so you're learning to drive, and I just took you on a rally, in a car with a loose wheel! Don't panic, we'll start with the basics next.
Simple Expressions
Open Firefox, and type about:blank in the location. Next, open Firebug in a separate window (Ctrl F12) – Firebug may ask you if you want to debug this special (internal) document, so say Yes. Click on the Console tab, then choose Options and select Larger Command Line.
Now let's try some literals. On the Command Line type:
3
Then press the Run button, or press Ctrl Enter. The result should be:
3
That's an example of a numeric literal. Not too exciting, so try this:
Math.PI
Then press Run. (I won't keep telling you to press Run from now on). The result should be:
3.141592653589793
That's an example of a numeric variable. Let's keep experimenting:
typeof 3
The result is:
"number"
Ok, so our numeric literal
3 is a
number type. (And so is
Math.PI, try typing
typeof Math.PI). So let's try a simple maths expression:
3 + 4
And the result is, surprisingly enough:
7
Something a little more difficult?
3 + 4 * 7
Which gives the result of 49. Whoops, no it doesn't...
31
So JavaScript can't do maths? Not quite. You probably read that last expression as 3 plus 4 equals 7 by 7 equals 49. But JavaScript, as for any other programming language, uses
precedence rules for all operators, including
arithmetic operators. We can change the precedence by using parentheses (because parentheses have a higher precedence than
+ or
*):
(3 + 4) * 7
Which now gives:
49
Better. But watch out, because JavaScript uses floating point (double-precision 64-bit format IEEE 754 values), which is
inaccurate some of the time:
3.1 + 0.2
unfortunately gives:
3.3000000000000003
Something to be aware of (and not just in JavaScript).
Normally, you'd define a numeric literal as a base 10 number, but you can use Octal (
0666 gives
438 decimal) or Hexadecimal (
0x16 gives
22 decimal). Javascript also defines three other numeric values
Infinity,
-Infinity, and
NaN. The first two should be reasonably obvious,
1/0 and
1/-0 will give these values.
NaN stands for
Not a Number,
0/0 will give this value. Unlike any other numeric value
NaN cannot be compared against itself
NaN == NaN is guaranteed to be
false, so use
isNaN(number) instead.
Apart from numerics, JavaScript can also handle
strings. For example:
"hello"
Gives:
"hello"
Nothing radical here. You can use single or double quotes as the string delimiters. If you need to add special characters to the string (perhaps embedding a quote), use the backslash character to escape the special character:
"\"hello\", he said"
gives:
""hello", he said"
Something more complex:
"Backslash is \\ and also \u005c"
gives:
"Backslash is \ and also \"
The
Unicode code point for backslash is
U+005C hexadecimal.
Syntax Errors
By now, you're getting closer to actual programming code (albeit in very small amounts), so it won't be surprising if you start getting a few syntax errors. A syntax error is a mistake made by the programmer, which the interpreter/compiler cannot correct – such as forgetting to terminate a string:
"Unterminated string\"
gives:
SyntaxError: unterminated string literal
A little patience, and you'll be able to figure out where you went wrong.
JavaScript uses the + binary operator to concatenate strings:
"hello " + "world"
gives:
"hello world"
Note, however, that 'adding' strings and numbers together always results in a string:
3 + "4"
gives:
"34"
and not 7, as would happen in Perl, for example. So non string types get coerced to string types before concatenation with strings.
The type of a string can be found by typing:
typeof "hello"
which gives:
"string"
Finally, let's look at boolean literals. Type:
true
which gives:
true
Now let's check the (other) boolean literal type:
typeof false
gives:
"boolean"
Simple Variables
Looking to the next stage, we'll create some variables. To create a variable, we start with the
var keyword, followed by a name, the
assignment operator (
=), a value, then a semicolon, which is the statement terminator:
var myFirstVar = 1;
which gives:
Exactly. It gives nothing back at all. Expressions evaluate to a value, statements don't. However, all is not lost, click on the Script tab, then click on New watch expression... and type this. You should see the myFirstVar variable and its value of 1. Let's see if this is so. Click on the Console tab and type myFirstVar which should result in:
1
Variable Names
In JavaScript variable names (and function names) must start with a letter or underscore (
_) and can then be followed by letters or numbers. All names are case sensitive, so
myvar is a different variable to
myVar. Traditionally, JavaScript uses
lowerCamelCasing for names.
You can't use
reserved words as a name, and unfortunately, JavaScript has a lot of them.
Now let's create another variable:
var mySecondVar;
Typing mySecondVar gives:
Still nothing. In this case, we have not given a value to the variable, so it can't give one back. Just to make the point, type:
typeof myFirstVar
which will give:
"number"
and then type:
typeof mySecondVar
which gives:
"undefined"
When a variable is declared, but not initialised, JavaScript gives it the special value of undefined. We can test for this condition, using a comparison operator:
typeof mySecondVar == undefined
which gives:
true
Note the comparison operator has two equals signs (==) to distinguish it from an assignment operator (=).
There is one other special value which we can give to a variable; the null value. This is used when we wish to specifically initialise a variable to nothing. Not a number, or string, or anything else, just nothing. That might not sound very useful, but it is; think about a function that looks up a name, if it finds the name it will return a record of some sort, but what does it return if it can't find the name? Exactly, it returns null.
Simple Functions
Functions allow us to group a set of statements under a single name. More than that, we can supply parameters to a function, and get a result back. Remember our vowel counting exercise? If we wanted to count the vowels on any string we could make a function for it. All we'd need to do then would be to pass the string to be counted as a parameter, and let the function give us back the count as the result.
Let's try that, type:
function countVowels(str) {
return str.match(/[aeiou]/ig).length;
}
Italian Curly Brackets or Parentesi Graffe
If you have an
Italian keyboard, you probably won't find the curly brackets, '
{' and '
}' anywhere. On an
English/American keyboard they are the first and second keys to the right of the '
P' key, but with the
Shift key pressed. If you don't press the
Shift key you get the square brackets, '
[' and '
]' respectively. I'll call these keys
bracket left and
bracket right for now.
You can access the square brackets on an Italian keyboard by using Alt Gr and bracket left or bracket right. You can also access the curly brackets with Alt Gr plus Shift and bracket left or bracket right.
Next, let's try out our function by typing:
var definition = "A series of instructions that a computer can interpret and execute";
countVowels(definition);
which gives
23
Good to know. So let's take a look in a little more detail. To create a function, we start with the
function keyword, followed by a name, the open bracket, a comma separated list of zero or more parameters, the close bracket, then the open curly bracket, zero or more statements, and finally the close curly bracket:
function name([param] [, param] [..., param]) {
statements
}
If we want the function to return control to the caller, then we use the
return keyword, possibly followed by a value.
One last point for now; the parameter name does not have to match the name of the variable passed to it. Inside the function, we use the parameter name to reference the parameter, outside the function we use the actual variable name. Think of it as a sort of alias. In our example above we pass the variable definition, but inside the function it is seen as the parameter str.
Conditional Expressions
A conditional expression allows us to make tests. This is a fundamental building block of any programming language. It allows us to ask questions, such as “is the sum greater than 10?”. Conditional expressions evaluate to a boolean value of true or false. Let's try a few examples, using the built-in Boolean() method. Type:
Boolean(3 > 2)
which gives
true
Of course you can use variables instead of literals. Try
Boolean(myFirstVar > 2)
which gives
false
because myFirstVar is (still) equal to 1.
Experiment with other conditional expressions for yourself. You can use >, <, >=, <=, == and != for the binary conditional operator. The last two operators represent “equals”, and “not equals”, respectively. Multiple conditional expressions can be made using the || and && conditional operators. The first is the “or” operator, the second is the “and” operator.
Now try this:
Boolean(4 == '4')
which gives
true
Again, when comparing a number to a string, JavaScript coerces the number to a string. There are two other conditional operators which avoid coercion; === and !==, “strict equals”, and “strict not equals”, respectively. Try this:
Boolean(4 === '4')
which gives
false
Quick! What values are false in JavaScript? The numbers 0 and NaN, the boolean false, the values null and undefined, and the empty string "". Everything else is true.
Simple Conditional Statements
The simplest test we can perform in JavaScript is the
if...else... statement. To see what happens, we'll create a simple function, with a basic
if...else... statement:
function ifTest(expr) {
if (expr) {
return 'passed';
}
else {
return 'failed';
}
}
Now let's try it out. Type:
ifTest(true)
and you should see:
"passed"
Type:
ifTest(false)
and you'll get:
"failed"
So we have created a function similar to the built-in Boolean() function. Try passing some of the previous conditional expressions to our new function:
ifTest(3 > 2)
which gives
"passed"
The
if...else... statement can be nested. Let's say that we want a function which gives grades according to a percentage scale:
|
Grade
|
Percentage
|
|
A
|
90% or better
|
|
B
|
80% or better
|
|
C
|
70% or better
|
|
D
|
55% or better
|
|
E
|
40% or better
|
|
F
|
Less than 40%
|
This can be done with multiple statements, thus:
function calculateGrade(percent) {
if (percent >= 90) {
return 'A';
}
else if (percent >= 80) {
return 'B';
}
else if (percent >= 70) {
return 'C';
}
else if (percent >= 55) {
return 'D';
}
else if(percent >= 40) {
return 'E';
}
else {
return 'F';
}
}
This works because when the first conditional expression resolves to true, then that expression's code block (the statements inside the curly braces) will be executed, and all the remaining else if or else statements will be skipped.
Because the simplest form of
if...else... statement, such as the one we used in our
ifTest() method, is so commonplace, there is a shorthand ternary operator which can sometimes be used instead:
function ifTest(expr) {
return (expr) ? 'passed' : 'failed';
}
Finally, to conclude today's lesson, we'll look at the
switch statement. This type of statement can be useful where you have a large set of known values which must be matched. In this case a switch statement can be more concise. In this somewhat convoluted example we'll check for certain 'magic' numbers:
function magicNumber(number) {
var result = null;
switch (number) {
case 3.14:
case 3.142:
case 3.1416:
result = 'Approximation of Pi';
break;
case 0:
result = 'Freezing point of water (Centigrade)';
break;
case 32:
result = 'Freezing point of water (Fahrenheit)';
break;
case 100:
result = 'Boiling point of water (Centigrade)';
break;
case 212:
result = 'Boiling point of water (Fahrenheit)';
break;
default:
result = number + ' is not magic to me';
break;
}
return result;
}
Try typing:
magicNumber(3.14)
which should give
"Approximation of Pi"
But
maginNumber(3.1)
gives
"3.1 is not magic to me"
Wow! Buy one new keyword (switch) and get three extra (case, default and break).
Within the switch code block (the code surrounded by '{' and '}' after the switch expression), we set a label for each case we wish to test. After the label value comes a colon (:), and then the statements for the given case. The statements are terminated by the break keyword and a statement terminating semicolon (;).
There is also one special case label called default, which handles all cases not specifically defined by the case labels.
You can use switch statements on strings as well as numbers.
Care Required with break;
Take great care with those case label: ... break; sequences. If you forget a break; the code will continue executing the statements of the following case label. This may be desired in some cases, but it's usually a sign of an error.
What's Next?
Next we'll start using a more permanent development environment, using Aptana Studio.