How did you do that?If you visited this page from the previous one and you filled in your name as requested, then the page should start with a personalised greeting. (If you wandered in from somewhere on the net, then there will be no greeting, and if you clicked on the reference at the top of the first page - well, perhaps you should try that out sometime)!How did we do this? Well, there were three components:
Let's look at each of these in turn:
See how this is structured. We have plain old text that asks "What is your name?",
followed by two form controls, a "text" input that merely creates a
text box that you can type into, and a "reset" button. We use the text
input - we've called it 'yourName' - to obtain information.
There is no "submit" button, as we would normally expect in a form,
and as you will soon find out, we abuse the reset button terribly!
But wait a minute! What's this GoThere function within
the reset button? Is this something that is mysteriously defined
inside JavaScript? No ways! If you were to
go back to the previous page and look at the source code (don't do so
just yet), then hidden in the body of the html code you would find
something like the following:
This is the mysterious hidden function that transforms our useless form
into something rather useful. How does it work?
Well, the first thing to note is that when we click on the reset button,
something happens. Javascript detects that we have clicked, in
other words, than an event has occurred.
And because we have inserted the magical invocation
OnClick='GoThere(myform.yourName)'
into the code for the reset button, JavaScript knows what to do .. it
looks for the function GoThere, wakes it up, and passes it
the information (contained in parenthesis). What is that information?
Well, we've called the form myform, and we helpfully labelled
the text input within the form yourName, so it doesn't take
much imagination to work out that when we click on the button,
we pass yourName to the function called GoThere.
The above is a very important example of how JavaScript handles
events. Each and every part of a webpage
can have events associated with it. Here we use a mouse click to
launch a function that loads a new page. As we learn more about JavaScript,
so we'll learn which events can be used for what. But for now, let's
be content to explore the OnClick event that we've created.
The first thing we note is that it's generally quite okay to hide
JavaScript within the body of a html document, as we did on the
first tutorial page. We won't do this much
(mainly because we like everything upfront) - the only reason why we
didn't put the above code into the header of the previous page, is
that it would have confused you had you clicked on View Source as we
invited you to do, near the start of that document!
What does the function do? Well, it's rather sneaky. It sets
location to a new web page address .. part2j.htm .. and, Hey Presto!
this page is loaded into the browser. But we do something even more
sneaky - we take the name you typed in and add it to the
web page address, preceded by a so-called "pound-sign" (#) - I usually
call this # a 'hash' (although the name 'tictactoe' is really cute)!
In other words, the following fragment..
"part2j.htm" + "#" + yourname.value; takes three little strings and joins them together (concatenates them).
The name "part2j.htm" is joined up with a "#" character, and then
with the string that you typed in, and was stored in yourname.
Note how we say yourname.value - another one of these irritating
little JavaScript rules - we passed the function the whole object, so
we should refer to its value!
What does this #name mean? You know the answer already - it just
tells the browser to go to a certain point in the web-page, with a
name the same as the one you typed in! But wait a bit, that name
can't possibly exist in the web-page we referenced, can it? Hmm.
Maybe not, but does the browser care? The short answer is "Not much"
- you can see that we now have a really rather cute way of passing
information from page to page. Just send the information after the
web-page name, preceded by a #.
We're two thirds of the way through our explanation. Now all we
need to know is how on earth the web-page receiving the information
makes use of it, printing your name at the top of the page. Here goes..
This means that if we have a function that can dynamically
write to the web-page, this dynamically written part of the web
page will appear on our screen before the rest of the page. What
is this wonderful function that dynamically writes to a web-page?
It's called:
document.write()
Anything in parenthesis is written into the web page. For example,
the code that greeted you at the top of the current page was generated more
or less as follows:
Let's work through this line by line. The first line tells us that
we can pull the information we sent out of the web-page address.
It's stored in part of the window.location object, and the
name of that part is, surprisingly enough, 'hash'! Note that this
includes the leading '#', so we clip this off using the function
substring(1), which gives us the contents of hash starting
at the second character (remember that in JavaScript, we start counting
at zero)! See how we got away with not saying var yourname ..,
as JavaScript is fairly tolerant and allows us to just make new variables
on the fly without explicitly declaring them.
The second line uses our wonderful function write to write
to the document. So do the third and fourth lines. What do they write?
Look carefully. First they write a
<div align='center' >
followed by a <h1> heading.
The string that is being passed to document.write
is in "double quotes", so when we use the align='center' instruction, we
encase the word 'center' in single quotes. This prevents the confusion
that we would cause if we here used double quotes again, and is really
necessary.
Next, we write "Hello ", followed by the name we so carefully
extracted from the location.hash. Finally we close off everything,
and for good measure, include a horizontal rule <hr>
Whenever you've written some really cute code, it's a good idea
to sit back, take a deep breath, and then ask "Well what can go wrong?".
There are in fact at least three things wrong with the above code, cute
as it is. Yes, it will generally work, but it needs to be dressed up
a little. Here are the problems..
Try this if you don't believe me! What's the problem? Well, IE
doesn't like sending certain characters as part of a hash name. One of
these is the space. So IE kindly translates the character into what
it regards as a useful rendition of that character. It does so by
(1) putting in a percentage sign and (2) giving the two-digit hexadecimal
code for that character, which, in the case of 'space', just happens to
be 20.
How do we fix the problem? How does this work? We already understand how we pull out yourname.
The function indexOf just tells us whether the string "%20" exists
inside yourname. If it doesn't, the value returned will be -1, but
if it does, then the number returned (and stored in posn) will be
the position in yourname of the first "%20", counting as always
from the left and starting at zero.
We then use this value posn to snip up the string, and replace
the "%20" with a space. Note how the new command while allows
us to do this again and again until no more "%20"s are found! And that's
it!
Before we rush off and implement this code, however, let's look at
our other problems.
Fortunately, there's an easy fix to this one. Simply insert the
line:
The above code assumes that you've already acquired yourname as
before. Is this the end of our troubles? No, not really. For it turns
out that Netscape doesn't like names with spaces in them. So if
we submit a name that contains spaces, then Netscape (although it
doesn't translate them into %20's) won't see this string as a name,
and so will churlishly go to the end of the document again.
What's the solution? Well, we're now having trouble with
spaces from both IE and Netscape. There are a million solutions, but
the snippet of code we would use is as follows (We insert it into
our original GoThere function, killing the problem at the source)..
You can see that the above code is very similar to that we proposed
as a fix for "%20"s. What it does is replace all spaces with _underscores_!
Once we've done this, the Netscape problem disappears (underscores are
fine within a name), and IE no longer translates our spaces into %20s,
either. Of course, for the sake of prettiness, we should perhaps translate
the underscores back to spaces, but that task is well within our means.
Fortunately, handling all of these problems is well within our
new-found capacity. An idea! Why don't we make a function like this:
How does this work? We pass three arguments to the function:
target, todo and withwhat. The function then looks
for todo inside the string target, and replaces it with
the string withwhat, doing so repeatedly until finished, at
which point it returns the altered value using return fixme.
(You can work it out .. fixme and atpos are just temporary
variables). We might 'invoke' this function as follows:
In addition, we lied to you. Well, perhaps that's a bit strong.
We concealed the truth. For (as you might have guessed) we couldn't
resist the temptation to use our previous IE3 detecting code, and
so we actually passed control from our first page to an intermediate
page (called part2.htm) which traps IE3. You can visit this page
by clicking here.
Note how on the first page, we had a little cop-out below our fancy
"Visit the next page" button - to at least allow non-JavaScript enabled
browsers to visit our explanatory page.
Note that our page construction is a teaching exercise - you
shouldn't do this sort of thing in a 'real' web-page without extensive
modification! For example, if yo use our #information trick, then
perhaps it would be a good idea to take a tip from Microsoft, and
translate unwanted characters to their hex codes, preceded by a %
(Later we'll encounter two functions - escape and unescape
that you can use to do the translation for you)!
And use tricks like hijacking reset buttons sparingly, if at all! (There's
a better way of making a button that we'll explore when we make
our JavaScript calculator at the end of this page). By the way, can
you think of any other potential problems with the way we've done
things above? (Heh)!
Creating and using variablesIf you've diligently read both the preceding page and this page, then you know there are two ways you can create variables in JavaScript:
For example, you can define a variable thus: var my_version = parseInt(navigator.appVersion); (where have we seen this before?), or you can simply say something like: yourname = window.location.hash.substring(1); where we've never used the variable yourname before, yet JavaScript somehow decides that (a) this is indeed a variable, and (b) it must assign it the value provided. Hmm, think about this. Firstly, why should there be two ways of creating variables, and secondly what are the consequences of wildly creating variables just by using their names? Another ugliness in JavaScript. The answer to our first question is that there are two different classes of variables, called global and local variables. Generally you should always use local variables - these are the ones you were first introduced to, the ones you created by using the word var. Local variables are just that - they only have meaning 'locally' - for example, in the function in which they were defined. This is a good thing! Occasionally you might want to have a variable that can be seen anywhere and everywhere. Then you would use a global variable, which you create by simply using its name! (It is a complete mystery to us why the makers of JavaScript didn't have some formal way of defining a global by, for example, using a keyword like global, or something!) We should also possibly say something about variable names.. Variable namesHow do we name a variable? Here are the rules:
And that's pretty much it! Later on we'll talk about the values contained in variables, and the different types of variables. C what I can do!The following sections are rather heavy - rush through them, and then come back when you get stuck, rather than painstakingly trudging through every syllable! JavaScript has many features in common with the language C. Apart from the common operators you would expect:
(By the way, unary minus takes a single argument and changes the sign, for example - fred gives the negative of the number contained in the variable fred) Where were we? Aha, we also have the following very C-like operators:
Don't be intimidated by these. Use will make them familiar -
you'll find that these are often very powerful operators. Not, of course,
as powerful as say, regular expressions in Perl, but powerful nevertheless.
Intermittently even more convenient than the above are the following:
In addition, there are a host of bitwise operators, that
act on a number bit-by-bit. We won't explore these here - see our
'Binary, schminary' section below.
Note the difference between = and = =
You write == as two equals signs one-after-the-other; we left a tiny
gap in between them in our text above as otherwise some fonts have the
two equals signs running into one another, which is really confusing!
Bodmas and friendsIt won't surprise you to learn that, in common with languages such as C, C++ and Java, JavaScript understands ordinary old infix notation where we say things such as:a + b * c and this is translated as a + (b * c) In other words, the rules of precedence are those you would expect - Brackets come before division and multiplication, which in turn take precedence over addition and subtraction. (In junior school you possibly learnt about this rule as 'Bodmas')! Here are the (slightly more formal) rules of precedence for JavaScript:
You can see that things rapidly become 'non-trivial' and confusing. Don't worry about all the strange <=>!@#&$%^ stuff! We'll gradually introduce you to the important things as we work through our tutorial. For the time being, just remember that operators on the same level have no precedence over one another! For example, * and / are on the same level, so expressions containing both are simply 'parsed' from left to right. We suggest that where there is possible ambiguity you: Use parentheses liberally .. they generally make things crystal clear. (But not nearly as clear as our favourite, Polish notation, which most programming languages understand about as well as they understand Polish. Go learn Lisp)! Typing (no, not QWERTY)!Think about it - there are different data types. You have, for example, integers, strings (we know what strings are from the first part of this tutorial), but what about logical values (true or false, as tested for by an if statement), and even floating point numbers? How does JavaScript distinguish between these various types? Well, to tell the truth, it more-or-less doesn't!JavaScript is a weakly typed language. This means that the variable fred (for example) can, at different times, contain a number, a string, a Boolean value (true/false) or even a floating-point number. It can even become an object! Which, incidentally, is an almost complete list of the different data types in JavaScript. Here they are, in a list:
( The example 0xff simply refers to a hexadecimal number. Don't worry about this for now, and never worry about octal, which can also be represented in JavaScript, but is obsolete)! This approach of being able to change the type of content in a variable on-the-fly may seem sexy, but it carries with it a host of problems. One of the most irritating is the following:
Point made. JavaScript will automatically coerce a variable of a particular type into an appropriate one. This seems fine, but where something has an ambivalent value ("5" is both a string, and a number) unexpectedly horrible things can happen. In yet other circumstances, where there is no "correct" answer, an error may result. The 'rules' state that strings are (generally) favoured over other data types, so, if you want to work out what 3 + "5" is, then the answer is "35" and not eight, as you might expect! (Next after strings come floating point, then integers, and finally logical operators). So numbers are converted to strings, and logical values to 0 or 1 (for false or true). It is thus important to be able to explicitly convert between types (to be able to force such conversions). How do we do this? We use conversion functions. Here they are:
Earlier documentation says that if parseInt doesn't find a number at the start of the string, it returns zero. In fact on more recent browsers, both parseInt and parseFloat return "NaN" (which stands for "Not a Number") if they don't find what they're looking for. Even more confusing than NaNs are nulls and null strings: Null strings and nullLet's start with a null string. Here's a null string:"" Simply two quotes, with nothing in between. You might thing that such a peculiar animal has no use whatsoever, but we've already used a null string above, extracted for your pleasure here:
in our final incarnation of the GoThere function we defined. We replace a single quote with - yes - the null string (that is, nothing). null is a very special (and confusing) thing. If I say something like:
.. and I haven't yet allocated a value to fred, then an error will result. Depending on how your browser is set up, you'll either get a mildly confusing error message, or the browser will simply stop interpreting the JavaScript! The correct solution is to prevent this sort of error by checking your script carefully. Okay, occasionally you might need a distinct value (different from all others) that you can initialise a variable to, but the JavaScript value of null which acts as this sort of 'place-filler' to prevent an error, is likely to be more of a problem than it's worth. I would avoid it. An example of how null might mess you around is provided when we look at automatic type conversions - null is converted to "null" for string operations, false for logical operations, and 0 for numerical operations! Escaping confusionThere are a few more things you need to know about strings. When Bill Gates cobbled together DOS, he chose to use the \backslash character to describe the path to a file (unlike Unix, which uses a /slash). In JavaScript (as in C and C++) we have a very different use for the backslash character - we use it as an escape. What do we mean by this? Well, certain characters (such as a "quote") will cause confusion if used in a string. We've already found one way to get around this - use single quotes, for example in:
Another is to escape the character. We could have rendered the above as:
You choose the method you want. For certain characters, an escape is extremely useful. Here are a few more characters - you need only remember the first:
Much later on we'll encounter another quite different 'escape' - there's actually a function called escape() which does what Microsoft did above - turns all the funny characters in a string into percentage signs. There's even an unescape() which turns things back again. At several points we'll find that, with the whole English language to choose from, our JavaScript developers had such an impoverished vocabulary that they had to use the same word for somewhat different concepts! Binary, schminary (with a touch of Logic)This section does assume that you (more-or-less) understand hexadecimal arithmetic (You have no excuse, as we explained it in our html tutorial). Here we delve into binary (base two) arithmetic.
On the previous page we explored the if { } else { }; statement. We therefore know a little about Boolean logic - how statements can be either true or false, and how we can combine such 'truths and falsehoods' using the || and && operators, as well as the ! operator which turns things around (false becomes true, true becomes false). What we have not yet told you is that similar logic can be applied to numbers .. we can for example take the number 3 (binary 11) and perform an AND operation on it with, say, the number 1 (binary 01). We could say something like:
What is the answer, and what does it mean? When we AND two numbers together, what is done is that corresponding bits are ANDed together. A "1" is regarded as being true, and a "0" as being false. The usual Boolean rules apply, so 1 & 1 gives 1, all other possibilities give zero. Anding 3 (Boolean "11") bit-by-bit with 1 (Boolean "01") gives us "01", as you would expect. Similarly | is used to OR together two numbers. For example,
(hexadecimal) There is one other Boolean operator you occasionally might come across. It's called XOR (or 'exclusive or'). In a similar way to A AND B (which means BOTH A AND B), A XOR B translates as "this is true only if either A is true or B is true, but not both". It's like one of those passages with a light switch at both ends - if both switches are off, the light is OFF. At one end of the passage you flip the switch on and - Presto! - the light goes on. You then go to the other end and flip that switch into the 'ON' position and what happens? The light goes OFF again! An example of XOR on two hexadecimal numbers: As if this weren't enough, JavaScript allows you to perform other bit-orientated operations on numbers. For example, you can shift every bit in a number ONE BIT LEFT, so that binary 0111 would become binary 01110. There are two operations to shift things right (can you think why this might be?) Here is a summary of bit-related JavaScript operations:
The reason why we have two right shift operators is related to the peculiar (but logical) way that computers store numbers. Negative numbers are generally stored in two's complement notation. (The way this works is that, taking the binary value of the number, we change all zeroes to ones and vice versa, and then add one). It turns out that when we store negative numbers in two's complement notation, the leftmost (highest) bit of the number is always a one, and with positive numbers, this bit is zero .. we therefore call this the sign bit. You can see that right shifting such a number and not preserving the sign bit will muck things up rather. But, in a manner vaguely reminiscent of the Y2K problem, one can also store a larger positive number in the same space if we just ignore 2's complement. Here it makes no sense whatsoever to preserve the leftmost bit (it isn't a sign bit), so we have two different shifts. Chaos rules! ArraysAn array is simply a grouping of similar objects. In fact, because of the weak typing of JavaScript (and one other reason), it's possible to store dissimilar items in the same array! But we're getting ahead of ourselves. First let's say how we make and use arrays. We create an array Brad with say five elements by saying:Brad = new Array(5); We don't have to know beforehand how many elements there are in the array. We could have just said Brad = new Array(), and then created elements on-the-fly, as we will shortly learn. What's the difference? Well, if we specify the number of elements, then each element starts off with the offensive, nasty little value null, which we discussed above. Watch out for this, especially as some versions of JavaScript will return "undefined" rather than "null" as the value of these elements. Okay, how do we put something into an array? Easy: Brad[0] = "Any old string"; See how we use [ square brackets ] to refer to an element of Brad. This gives you a hint of how you pull something out of an array: var Janet = Brad[0]; will extract the value we put into Brad[0] and copy it into a variable called Janet. Note how the first element of an array has the index 0 - remember than in JavaScript, we count starting at zero! If the element you refer to doesn't exist, don't worry - JavaScript will create not only that element, but all the undefined elements 'lower than' it! There are still more tricks up our sleeves. We will next look at "pre-defined" arrays (otherwise known as "Dense Arrays"), and then at multi-dimensional arrays. Dense ArraysAssume you know the elements that will occupy an array. It makes sense to be able to 'set them all up' in one fell swoop, thus:Dwarfs = new Array ("Happy", "Sleepy", "Dopey", "Sneezy", "Oin", "Gloin", "Frodo", "Glod"); Multidimensional ArraysThere is no rule that forbids an array from having as one of its components, another array. This is rather clumsy, but a shorthand even exists for accessing elements of this 'sub-array'. Let's look at an example:
Here we create an array called square, with each element a separate array. The shorthand way of accessing each element is to refer to the element of the main array in the first square brackets and then the sub-array as the second. So square[3][2] gives us 81. (The real reason why JavaScript arrays can contain a variety of different data types is that they are actually Objects. For a detailed consideration of objects, see the third page of our tutorial). Trig and stuff!It's not that surprising that JavaScript has built into it a variety of mathematical functions. These include basic trigonometric functions, logarithms, and a few constants. Here they are:
Note how each and every one of these functions must be preceded by Math. - otherwise you'll get a confusing error message (or JavaScript will stop being interpreted). This is also true for constants:
Putting it all togetherWe've incorporated much of what you've learnt into designing a simple calculator. Alternatively, you can skip this and go on to our next lesson.
|