This contrast is a good one, because interpreted languages often look just
a bit clunky when compared with compiled languages. They are slower,
and somewhat 'artificial'. They are often less powerful too, although this
is commonly merely a matter of bad design. Compiled languages zoom along,
while interpreted languages crawl. (Of course, when compiled code crashes,
it often does so far more spectacularly than, say a script that doesn't work
properly. Think of someone having direct access to your nervous system,
controlling your every action, and then dropping the control into the
bathtub)!
Why then is JavaScript not a compiled language? Personally, I think
this is more a matter of history than reason - JavaScript started simply,
as a convenient way of knocking together a quick script, rather than
going through all the tedium and pain of writing something in say, Java
(which is a bugger to program in). You can also do things in JavaScript
that you can't in Java, because of the intimate relationship between
JavaScript and HTML. As HTML became more complex, so
did JavaScript. Now we have an almost fully-fledged language on our
hands, with an intimidating complexity, but not (yet) with compilation
as one of its features. Many JavaScript tutorials will tell you that
it's easy to program in. Yes, if you're prepared just to cut and paste
other people's code, or add frills to your web-page. A full grasp of
JavaScript is much more difficult to achieve, and something that has
been made difficult by the incompatibilities between Netscape and
Microsoft!
Things are made even more complex because although JavaScript now has
a defined syntax, it works together with a browser, which has a
completely separate "Document Object Module" (DOM) structure. Only
recently has the Worldwide Web Consortium (W3C) defined standard
"Document Module Levels" - the proprietary DOMs of IE 4 and Netscape 4
are often incompatible.
Try inserting the following code into a web-page that you've
created, and then load the page in either Netscape or Internet Explorer:
In addition, it is often useful to use your knowledge of the
browser to tailor your code to IE or Netscape. We'll show you how.
First, we need to identify the browser.
How do we use the above gobbledegook in a real script? Well, unfortunately we have
to understand what the above does to use it really effectively. And
that in turn means we have to know something about how JavaScript works.
First, let's go back to our very first script, the one that said:
<script language='JavaScript'>
<!--
alert ("Welcome to my JavaScript tutorial!");
//-->
</script>
|
It's clear that using the word alert in our script causes a
box and message to be drawn on the screen. Note how we invoked this magical
alert function - we write its name - alert - followed by something
in (parenthesis). The something-in-parenthesis is in turn followed by
a semicolon;
This tells you a lot about the syntax of JavaScript. A lot of JavaScript
is simply invoking functions that do things. We pass (information in
parenthesis) to the function, and the function does something with
the information. Our function alert draws a cutesy little
box with an "OK" button - we will end up using alert rather a lot (although
we'll try hard to avoid it)!
Let's look a little more closely at the (thing in parenthesis). See
how it starts and ends with "quotation marks". These are important because
they tell us that between them there is a string. A string is simply
a sequence of characters, for example "This is -- hmm - a string", or
"Thisisanextralongstringofletters", or even "!&(*$#*+!@,\
DAMN!".
Finally let's remind you of how the JavaScript statement ended - with
a semicolon;
No not a full stop. A semicolon;
Yes, that's right! A semicolon;
You now know enough to start understanding our second script.
Here it is again, combined with a modification of the first script!
My second script (complete!)
|
<script language='JavaScript'>
<!--
var whoami=navigator.userAgent.toLowerCase(); //use lower case name
var my_version = parseInt(navigator.appVersion); //get version
var is_ie = (whoami.indexOf("msie") != -1); //does name contain 'msie'?
var is_ie3 = (is_ie && (my_version < 4)); //is it version 3?
if ( is_ie3 )
{ alert ("Aargh! You're using Internet Explorer 3 !");
} else
{ alert ("Good! Your Browser appears JavaScript-competent!"); };
//-->
</script>
|
Although the first time you looked at the above, it probably scared you
witless, look again! Some order seems to emerge from the chaos.
You (at least partially) understand the first two lines, because they
are identical to the first two lines of our alert script.
Then we come across several lines that begin with var. What do
they do?
It appears that they set aside something with a name that
has a value. Look at the first of these lines - it says
var whoami=navigator.userAgent.toLowerCase(); //use lower case name
Something called whoami seems to be made equal to the complex rubbish
on the right hand side, after the = equals sign. And then, to cap it
all, the person who wrote this confusing line seems to have ended it off
with // two slashes followed by some sort of comment.
The next line is similar. And the next. It seems clear that in JavaScript
we can set aside new values (variables?) by starting a line
with var and then following it with the name of the variable.
In addition, on the same line we can give a variable a particular value
by setting it = (equal) to someting.
So it looks as if navigator.userAgent.toLowerCase is simply some
sort of glorified function (After all, it's followed by parenthesis).
And so is parseInt, and so indeed is whoami.indexOf ! This is not
quite the whole answer - but it's a good approximation.
In addition, we have learnt at least one way of putting a comment
into JavaScript. If you put // on a line, then everything afterwards
is ignored (for that line alone) - it's treated as a comment.
/* Just as an aside, there's another, more general, way of creating
a comment in JavaScript. You start the comment with a slash followed
immediately by a star, and end the comment with the reverse - a star
followed by a slash */ The great thing about this sort of comment is
that it can extend over several lines, or even occupy /*just a part*/ of
a line!
Don't worry about the exact meaning of the lines we've just looked at -
all will eventually become clear!
|
4. Deeper still - the if statement
We look deeper still. Ignoring (for the time being) the meaning of
the lines we've examined, we look at the subsequent four lines:
if ( is_ie3 )
{ alert ("Aargh! You're using Internet Explorer 3 !");
} else
{ alert ("Good! Your Browser appears JavaScript-competent!"); };
First, we examine their overall structure. Clearly a choice is being
made. If we merely read the lines as English we can deduce that
"if the browser is Internet Explorer 3, then we
alert ("Aargh! You're using Internet Explorer 3 !")
while in all other cases we say "Good! Your Browser appears JavaScript-competent!"
So we now know how to make a decision in JavaScript - in other words,
we can test for a condition, and respond according to the results of a
test. Clearly, it is an if statement that does this testing. Just
as clear is the format of the if statement:
if ( /*condition being tested*/ )
{ /* do this if condition is met */ }
else
{ /* something else to do if condition NOT met */ };
See how we use curly brackets {braces} to show the start and end
of the various sections. Alert readers will have noticed that in
my "second script" the braces were positioned slightly differently from
those in the above 'skeletonised' if statement. It doesn't really matter,
as JavaScript can and often does extend over several lines. I just happen
to like the way I wrote the if statement the first time around.
But there is something important in the above and this something is
not immediately apparent. Notice how there is NO
semicolon after the first set of braces that make up the if..else statement.
This is important! If you put in a semicolon, things won't work!
you should now fully understand the above if statement, with
one exception. You don't understand the part of the statment that reads
if ( is_ie3 )
Clearly, something is being tested, and that something is the
is_ie3 that was created in the line:
var is_ie3 = (is_ie && (my_version < 4)); //is it version 3?
So. If we really want to understand the value in is_ie3, we
have to fully understand what's going on in the var line where
it is defined, the line that reads:
var is_ie3 = (is_ie && (my_version < 4)); //is it version 3?
Now we know what var means, and we know that is_ie3 is
being made equal to something by the = equals sign. So all we
need to understand is the following:
(is_ie && (my_version < 4))
What on earth can this mean? Well, let's see. The previous line
has defined is_ie and we can easily deduce from its name
that is_ie probably tells us whether we're dealing with
Internet Explorer (true) or not (false). Similarly, the part of
the statement that reads:
(my_version < 4)
almost certainly is true if the version of Internet Explorer is
less than 4, and false if this is not the case.
It doesn't then take a great leap of imagination to deduce that
the peculiar && links the two. In other words:
(is_ie && (my_version < 4))
translates as:
it's internet explorer AND the version is under version 4
We can therefore confidently deduce that the line we've just examined
sets is_ie3 to true if we're dealing with internet explorer AND
the version number is under version four. Otherwise, is_ie3 becomes
false. This value of is_ie3 is then used in the next line (the
if statement).
The above is a very simple example of Boolean logic. Boolean logic
is about statements that are either true or false. Clearly, we can
combine statements together. Two statements can both be true,
both can be false, or one can be true and the other false. We now
know how to test in JavaScript whether both statements are true - we
just use && to link the two together, and then put the
whole thing in parenthesis. For example, if we want to test whether
A is true AND B is true, we say
( A && B )
How do we test whether EITHER statement is true, in other words,
whether A is true OR B is true (or, indeed, both are true)? Easy:
( A || B )
will do the trick. (Different keyboards have the |pipe| character
in different positions. Often it's near the \ backslash character on
your keyboard. Look around)! Finally, we need to know if something is NOT true.
The syntax is just to use an exclamation mark:
( ! A )
Let's look once more at our second script:
My second script
|
<script language='JavaScript'>
<!--
var whoami=navigator.userAgent.toLowerCase(); //use lower case name
var my_version = parseInt(navigator.appVersion); //get version
var is_ie = (whoami.indexOf("msie") != -1); //does name contain 'msie'?
var is_ie3 = (is_ie && (my_version < 4)); //is it version 3?
if ( is_ie3 )
{ alert ("Aargh! You're using Internet Explorer 3 !");
} else
{ alert ("Good! Your Browser appears JavaScript-competent!"); };
//-->
</script>
|
We are just beginning to understand what's going on. We set up four
variables - whoami, my_version, is_ie and
is_ie3. The first presumably contains a "string" that identifies
the browser being used, the second tells us the version of the browser,
the third tells us if the browser is internet explorer, and the fourth
whether this is version 3 (version number under four && internet explorer).
We then use an if statement to either harrass the unfortunate user, or
compliment her.
Armed with this knowledge, let's look at the mysterious line:
var whoami=navigator.userAgent.toLowerCase(); //use lower case name
in a bit more detail. Notice how we have a strange sequence of words linked
together by dots, thus: navigator.userAgent.toLowerCase
This is typical of Object-Orientated Programming (OOP). The idea behind
OOP is that we have things called "objects". These objects have two
distinct attributes associated with them. They have:
- properties
- methods
The commonly-used analogy is to a motor car - it has properties:
the paint is red, it has five wheels (including the spare), and so on;
it also has methods - start the car,
take off the handbrake and so on. (Can you tell the difference
between a method and a function? I'm not sure I can)!
Trivially, one would suppose that you could say things like:
car.paint="red";
car.start();
and so on.
Let's put this in context.
- navigator.userAgent refers to
an object called navigator that has a property called
userAgent.
- navigator.userAgent.toLowerCase() takes
that property, applies the method toLowerCase to the property,
and gives it to us.
Clearly all this does is give us a string that
contains the name of the internet browser we are dealing with, after
this string has been converted to lower case.
If you were brought up on more traditional computer programming
languages, you'll see that OOP doesn't do anything that cannot be
done in traditional computer languages. It's just a different way
of looking at information and how we handle it. (Later on we will
explore the merits and demerits of OOP). With JavaScript, we're
stuck with OOP, so it's a good idea to get to know it.
Let's now look at all of our OOP-style statements:
- whoami=navigator.userAgent.toLowerCase();
- my_version = parseInt(navigator.appVersion);
- is_ie = (whoami.indexOf("msie") != -1);
We can deduce a lot from these statements. The first tells us that
all browsers that understand JavaScript have an object called navigator
and that this has a property called userAgent. The second tells
us that navigator has another property, appVersion.
The third statement is even more interesting, because it tells us
that something we have created will automatically (automagically?)
acquire certain methods that go with it. For we created the
variable whoami but look what we can do with it - we can
apply the mysterious method indexOf to it, and ultimately get an intelligible
answer - the value true or false that is put into is_ie, as we
discussed above!
This last observation hints at an important characteristic of OOP -
objects can "inherit" properties and methods. This is both very useful (you don't
have to potter around associating some commonly-used methods with an
object), and also a cause of immense frustration. Why frustration? Because
in any fairly complex object-oriented system (for example a web browser)
there is a massive proliferation of properties and methods, that can
confuse and mystify you if you want to sit down and tell the browser to
do something! Later on we will try and detail every property and method
of Netscape and MSIE, and you will see what I mean.
For now, let's just look at examples of the three methods we've been introduced to:
- toLowerCase()
- indexOf("string")
- parseInt("123abc")
With each of the above examples, we've included examples of 'arguments' that
the methods expect (within parenthesis). For example, indexOf
expects to be provided with a string, and parseInt should be
supplied with a string that starts with a number. toLowerCase doesn't expect anything,
so we've given it nothing but empty parenthesis.
It is obvious what toLowerCase does - it converts something
to lower case. For example, "FrED" might become "fred". indexOf is
a bit more puzzling, but let's look at how it's used (with the comment):
var is_ie = (whoami.indexOf("msie") != -1); //does name contain 'msie'?
Using our previously-acquired knowledge, we can work out the meaning
of this line:
we can now deduce what indexOf does - it gives us a number, and this
number presumably tells us where within a string, a particular sequence
of characters is located. If the number is "-1", then presumably the
desired sequence was not found.
Let's try an example. Say we have the sentence
"This is not a pipe". We'll try the following thought experiment:
var fred="This is not a pipe"; // create fred and allocate a value
var findis=fred.indexOf("is"); // find where the string "is" is located
Now quick - what should the value of findis be? (No, don't cheat and
page down before you've worked out the answer)!
Full marks if you said "2". My suspicion is that you said either six,
five, or perhaps three. Let's look at our experiment again:
var fred="This is not a pipe"; // create fred and allocate a value
var findis=fred.indexOf("is"); // find where the string "is" is located
Counting from the left, we see that the first character is T, the
second is h, the third is i and the fourth is s. So the third and fourth
characters of the string make up the string "is", which matches. So
why is the answer two and not three? Simply because grown up computer
languages count starting at zero!! So the 'zeroth' character is actually
T, the 1st is h, the 2nd is i and the 3rd is s. (I bet at least some
readers missed the "is" in "This" and jumped forward to the word "is"
later on in the sentence).
Remember this method of counting when you work with computers. Start
with zero!
7. Putting it together
We now know enough to create a precise English translation of our
previously obscure second script:
My second script (complete!)
|
<script language='JavaScript'>
<!--
var whoami=navigator.userAgent.toLowerCase(); //use lower case name
var my_version = parseInt(navigator.appVersion); //get version
var is_ie = (whoami.indexOf("msie") != -1); //does name contain 'msie'?
var is_ie3 = (is_ie && (my_version < 4)); //is it version 3?
if ( is_ie3 )
{ alert ("Aargh! You're using Internet Explorer 3 !");
} else
{ alert ("Good! Your Browser appears JavaScript-competent!"); };
//-->
</script>
|
.. translates as
- Create a string variable whoami and set it to contain
a string that describes the userAgent of the navigator
object that is browsing this page;
- Create another string called my_version that gives us
the version of the navigator (By the way, we haven't yet said what
parseInt does, but it's clear from the context that it
takes a string and pulls out the first integer it comes across -
a rather clumsy function that shows how some languages are simply
thrown together!);
- Find out whether the string describing the userAgent contains
the sub-string "msie". If it does, set the newly created variable
is_ie to true, otherwise set is_ie to false;
- If the version number is under four, and is_ie is true,
then set the new variable is_ie3 to true, but otherwise
make it false;
- If we are dealing with Internet Explorer 3, in other words,
if is_ie3 is true, then print the rude and damning message
"Aargh! You're using Internet Explorer 3 !" in a cute little box,
and otherwise:
- Congratulate the user for good taste with the message:
"Good! Your Browser appears JavaScript-competent!"
A piece of cake!