reptile7's JavaScript blog
Monday, May 29, 2006
 
Towards the Infinite Loop
Blog Entry #40

Suppose you are an engineer designing a process that involves a repeating operation. Being efficiency-minded, you naturally seek to automate that operation if at all possible. So it is with computer programmers - engineers themselves in their own way - who might want to execute repeatedly a given block of code; the automative tools available to programmers include:
(a) functions - recall, for example, the recursive guessnum2( ) function in Blog Entry #38;
(b) loops;
and at least as far as JavaScript is concerned, the window object has
(c) a setInterval( ) method that "[e]valuates an expression or calls a function every time a specified number of milliseconds elapses," quoting Netscape.

At the beginning (in "The Concept") of HTML Goodies' JavaScript Primers #24, Joe notes that JavaScript has two main looping processes: for loops and while loops, which we'll discuss respectively in this and the next posts. Syntactically, for and while loops, like if...else conditionals, are classified in JavaScript as statements, so I'll be coloring their text references green as well.

We've actually encountered for loops twice previously, specifically in Blog Entries #12 and #17, but we have yet to discuss them in general terms, so let's do that now. Courtesy of Netscape, the syntax of a for loop is given below; as you can see, it has obvious similarities with the syntaxes of functions and if...else statements:

for ([initial-expression]; [condition]; [increment-expression])
// as long as the central condition is true, execute the following code repeatedly
{
command_statement_A;
command_statement_B; etc.
}
/* as usual, the braces surrounding the command statements do not need to be on their own lines; also, as for if and else, the braces can be omitted if there's just one statement */

After the for keyword is a set of parentheses generally containing three expressions, all of which are in fact optional, as indicated by the square brackets surrounding them.

The initial-expression usually initializes a counter variable, which can be but does not need to be declared with the var keyword - e.g., x=1; - however, you can put other types of statements (window.alert("Hello World");, document.bgColor="blue";, etc.) here* if for some reason you wanted to do that.
(*This is also true for the increment-expression.)

The increment-expression is typically used to update the value of the counter variable as the loop runs; the counter variable is most often incremented (1 is added to its value) here by one of the following commands:

x=x+1 // or...
x++ // or...
++x
/* ++ is the increment operator; it can precede or follow the counter variable in the increment-expression */

For count-controlled loops, Wikipedia notes, "In most cases counting can go downwards [e.g., the counter variable can be decremented] instead of upwards and step sizes other than 1 can be used."

The central condition commonly compares the counter variable with some other quantity and is evaluated at the beginning of each iteration of the loop; if the condition is true, then the loop code in braces executes repeatedly, as noted above, but if and when the condition becomes false, then the loop stops.

If you would like a mathematical analogy, the execution of a for loop is somewhat like obtaining a definite integral, , which also involves a repeating operation (the product f(x)dx) carried out according to a starting point (x = a) and a condition (a ≤ x ≤ b) and whose end result is the sum of the returns of the operation.

Although each for expression is optional, the semicolons delimiting them are not (you'll get errors if you leave them out). Suppose you want to leave out the condition expression; the syntax would look like:

for (x=1; ; x++) {statements}

With respect to the preceding code, perhaps you are thinking, "Wouldn't this set up an infinite loop?" Not to worry - a for (or while) loop can be terminated at a given point by a break statement, for example:

for (x=1; ; x++) {
if (x == 4) break
statements}

The statements of this loop execute three times before the loop is stopped by the if (x == 4) break command line. In effect, the break statement brings the for condition into the {body} of the loop; moreover, the increment-expression can also be placed in the loop body, if desired. For its part, the initial-expression can be placed prior to the loop statement but not in the loop body (unless you really do want to set up an infinite loop).

Netscape notes that the JavaScript for loop is similar to the for loops of the C and Java programming languages and provides a sequence of events for a JavaScript for loop here.

We're ready now for a quick look at the Primer #24 Script:

<html><head></head><body>
<h3>We'll now count from one to five:</h3>
<script type="text/javascript">
for (i=1; i<=5; i=i+1) {
document.write(i + "<br>"); }
</script>
<p>...and we're done
</body></html>

For the most part (notwithstanding the i > 5 typo that begins the fourth list item), Joe's script deconstruction is well done and I encourage you to read through it. Anything new here besides the for loop itself? Yes, actually - the for condition introduces the <= (less than or equal to) comparison operator, equivalent to the ≤ symbol.

The loop in the script runs five times, once for each value (1, 2, 3, 4, and 5) of the counter variable i; the loop condition, i<=5;, evaluates to false after i increments to 6 at the end of the fifth iteration, so the loop stops at this point. For each pass through the loop, the command:

document.write(i + "<br>");

prints the value of i and includes a <br> tag for carriage-returning the next value of i to the next line, as shown in the script demo.

The Primer #24 Assignment

In the Primer #24 Assignment, Joe asks the reader to create a document that uses two for loops as timers to schedule two executions of code. In theory, here's the sequence of events that's supposed to happen for a working answer:
(i) the user initially sees a page with a white background and an <h2>Hold on to Your Hat!</h2> header;
(ii) a first for loop counts to 10,000;
(iii) the page background color turns yellow and the text string "Here comes another color surprise..." pops up;
(iv) a second for loop counts to 10,000; and finally,
(v) the page background turns pink.

In practice, all I see when I go to the assignment answer page is the end result, i.e., a pink page with the aforementioned <h2>Hold on to Your Hat!</h2> header and "Here comes another color surprise..." string; at best, the yellow background of stage (iii) above is observable for a split second, whereas the white background of stage (i) is not seen at all. However, my nonobservation of stages (i) and (iii) is easily explained; even my relatively ancient computer, with its 350-MHz processor, burns through a 10,000-iteration for loop in about 35-45 milliseconds when using MSIE, as determined by:

d0 = new Date( );
/* from Netscape's Date object documentation: "The date is measured in milliseconds since midnight 01 January, 1970 UTC." */
for (i=1; i<=10000; i=i+1) { } // the braces here are necessary! d1 = new Date( ); // d1-d0 returns 35-45 when using MSIE 5.1.6; d1-d0 returns 80-85 when using Netscape 7.02 "When was Primer #24 written, and what sort of stone-age machine was Joe using at the time?" I was wondering that myself (my attempt to find a Primer #24 mirror that brings the assignment 'up to date' was unsuccessful, BTW)...anyway, it turns out that I can get the assignment answer script to cleanly separate stages (i), (iii), and (v) sometimes, not always reproducibly, with MSIE when I beef up the number of for iterations to 750,000:

for (i=1; i<=750000; i=i+1) { } // in this case, d1-d0 ≅ 2800 (2.8 seconds) Functionizing the for loops also helps; after a bit of experimentation, I find that the following code executes satisfactorily 70-80% of the time, again when using MSIE:

<body bgcolor="white" onload="count2( );">
<h2>Hold on to your hat!</h2>
<script type="text/javascript">
function count1( ) {
for (i=1; i<=750000; i=i+1) { }
document.write("Here Comes a Color Surprise!...");
document.bgColor="yellow"; }
count1( );
function count2( ) {
for (i=1; i<=750000; i=i+1) { }
document.bgColor="pink"; }
</script></body>

Curiously, the identity of the preceding (history.go(-1)) page affects the display of my modified scripts. For example, when I go directly from http://www.google.com/ to a bookmarked file whose source contains the functionized-for-loops script, I usually see stages (iii) and (v) but not stage (i), but I see all three stages when I access the file from http://www.wikipedia.org/. Perhaps someone with a detailed knowledge of Internet Explorer and its JScript engine could explain this behavior, but I am not that person.

As for Netscape:
• Regardless of any alterations that I make to Joe's answer script, Netscape 7.02 evidently insists on reading through a document and interpreting its script parts before displaying anything, and all I ever see with this version is the stage-(v) end result.
• Bizarrely, with Netscape 4.79 (yes, I still have this on my hard disk) my demo page linked above displays as desired (if more slowly than with MSIE). Go figure.

I offer no guarantee that my answer script modifications will work for you, but even if your computer is five times as fast as mine is, then you should still briefly see stages (i), (iii), and (v) at my demo page (or at least I still see them when I lower the for iteration count to 150,000 - conversely, you might try increasing the for iteration count if you don't see stages (i) and (iii)).

More generally, it seems to me that in this assignment Joe is using for loops for a time-delaying purpose for which they are not really intended, and it is in fact much easier to schedule the (i)/(iii)/(v) script stages with window.setTimeout( ) commands (I thought of using window.setTimeout( ) commands in my answer, but that seemed like 'cheating'; the whole point of the assignment, after all, is to separate the (i)/(iii)/(v) script stages via for loops). The assignment still serves as an interesting exercise, however; quite often there is considerable instructive value in dissecting problems that are inappropriate for one reason or another.

Next up: Primer #25 and while loops.

reptile7

Thursday, May 18, 2006
 
The Randomizable If...else
Blog Entry #39

HTML Goodies' JavaScript Primers #23, "Producing Random Statements and Images," wraps up our tour of introductory applications of if...else statements. In accord with the primer title, the Primer #23 Script displays random statements, whereas the Primer #23 Assignment addresses the display of random images. A fairly simple strategy is at work in both situations: we'll use a modulo operation, discussed in Blog Entry #36, to generate a small set of random numbers, which are then associated, respectively, with an equal number of items - text strings or image files - via a series of if statements; once indexed in this manner, these items are then randomly written to the page by normal document.write( ) statements. In illustration, let's first look at the Primer #23 Script:

<html><body>
<script type="text/javascript">
var0="An Apple A Day";
var1="A Stitch in Time";
var2="Bird in the Hand";
now=new Date( );
num=(now.getSeconds( ))%3;
document.write("Random Number: " + num + "<br>");
if (num == 0) // if statement #1
{cliche=var0;}
if (num == 1) // if statement #2
{cliche=var1;}
if (num == 2) // if statement #3
{cliche=var2;}
document.write(cliche);
</script>
<p>....as I always say.
</body></html>

The now=new Date( ); num=(now.getSeconds( ))%3; code generates a random number num whose value is 0, 1, or 2, these being the possible remainders for divisions using 3 as the divisor.

Preceding the random number code are three statements that assign text strings, one for each random number value, to the variables var0, var1, and var2. These identifiers are not related to the var keyword used for declaring variables - more on this in a bit.

Following the random number code is first a document.write( ) command that displays the value of num (contra the primer, there's no need for this command to be all on one line - it's fine as it is originally) and then a series of if statements that connect the var0, var1, and var2 text strings to the values of num. Consider, for example, if statement #1:

if (num == 0) {cliche=var0;}

As you can deduce, this statement associates the "An Apple A Day" (var0) string with the 0 value of num, specifically saying, "If it's true that num and 0 are equal, then assign var0 and its value ['An Apple A Day'] to the variable cliche." Similarly, if statements #2 and #3 respectively associate the "A Stitch in Time" (var1) and "Bird in the Hand" (var2) strings with the 1 and 2 values of num.

If a given if statement's condition is true, then the conditions of the other two if statements are necessarily false and their {commands} will be ignored by the browser.

In sum, each if statement uses a specific value of num to assign a specific text string to cliche, which is written to the page by the document.write( ) command at the end of the script. Because num is a random number, then the script if statement (#1, #2, or #3) that executes is random and the displayed value of cliche is also random. Pretty straightforward.

Let's briefly get back to the var0, var1, and var2 variable names. In the "Deconstructing the Script" section of the primer, Joe says, "Notice that we DO NOT have the var num=num+1 in this one. It's not needed because we denoted our three variables starting with 0. If we started with 1, then we would need to." Joe is implying here that var0, var1, and var2 are indexed members of a var[i] variable array. (We'll take up the JavaScript Array object, and the variabilization thereof, in Primer #26.) Not so. A few comments in this regard:

• First, var itself is, not surprisingly, a JavaScript reserved word and is thus an unsuitable variable name; by extension, var[0], var[1], and var[2] (had Joe's syntax been correct, with square-bracketed index numbers) would also be unsuitable.

• It follows that the 0, 1, and 2 characters in var0, var1, and var2 are not index numbers at all, and thus var0, var1, and var2 are just ordinary variable names, no different from var3, var4, and var5 or from tom, dick, and harry for that matter.

• The real reason, then, we don't need a num=num+1 statement is that the conditions of if statements #1, #2, and #3 compare num with the numbers 0, 1, and 2. If we wanted to, we could add a num=num+1 statement and then compare num with the numbers 1, 2, and 3 (e.g., if (num == 1) {cliche=var0;} and so on), but this would of course be unnecessary.

As it appears in the primer, the Primer #23 Script works A-OK, and yet there's a sense of clutter here that rubs me the wrong way. Is it really necessary to variabilize the text strings? Do we really need to have two document.write( ) commands? Man, I just can't go any further until I rewrite this thing:

<script type="text/javascript">
now=new Date( ); num=(now.getSeconds( ))%3;
if (num == 0) cliche="An Apple A Day";
if (num == 1) cliche="A Stitch in Time";
if (num == 2) cliche="Bird in the Hand";
document.write("Random Number: " + num + "<br>" + cliche);
</script>
<p>....as I always say.

There. I feel much better now.

To reload or not to reload

"Having to reload the page to see different random numbers and quotes is somewhat of a pain."

I couldn't agree more. It'd be much more convenient if we could just click a button that renews the random number/statement in, say, a borderless text box, yes? Here's the code:

<script type="text/javascript">
function randtext( ) {
now=new Date( ); num=(now.getSeconds( ))%3;
if (num == 0) cliche="An Apple A Day";
if (num == 1) cliche="A Stitch in Time";
if (num == 2) cliche="Bird in the Hand";
document.f23.t23.value="Random Number: " + num + "; " + cliche; }
</script>
<form name="f23">
<input type="button" value="Click here to display a random number/statement below." onclick="randtext( );"><p>
<input name="t23" size="50" style="border:0px;">
</form>

Try it out (depending on your browser, more than one click may be necessary):


The Primer #23 Assignment

In the Primer #23 Assignment, Joe asks the reader to adapt the Primer #23 Script to the random display of images; he offers for the assignment three images - "pic1.gif", "pic2.gif", and "pic3.gif" - and provides two answer scripts, which are briefly discussed below.

(1) Assignment answer script #1: "Possible Answer 1 of 2"

Answer script #1 largely parallels the Primer #23 Script. Joe adds a num=num+1 statement to the random number code and then compares num to the numbers 1, 2, and 3 in the script's if statements (vide supra). The randomized image file is again assigned to cliche and the image is displayed via the following code:

quot="'"; // this is double quote, single quote, double quote which produces '
document.write("<img src=" + quot + cliche + quot +">");

For some strange reason, Joe chose to variabilize the single quotes that would ordinarily surround the src attribute value in the <img> tag; this is unnecessary, as these single quotes can be brought inside of the document.write( ) double quotes as follows:

document.write("<img src=' " + cliche + " '>");

(More sloppily, the single quotes here can also be omitted without causing any problems.)

(1) Assignment answer script #2: "Or if You are REALLY Clever"

Answer script #2 comes out of left field. Joe ditches the if statements altogether and instead applies the var1, var2, and var3 identifiers to randomizing the image file and displaying the image via the following command:

document.write("<img src=" + quot + eval("var"+num) + quot +">"); // quot="'";

Ah, our good friend the eval( ) function, which we briefly discussed in the previous post; once again, as in Primer #22, Joe says not a word here about eval( ) and what it does. So how does this command work? What's going on? It's pretty simple, actually. Suppose that num is 1. Concatenating the string "var" and the number 1 ("var"+num) gives the string "var1". (Netscape's "Data Type Conversion" documentation notes, "In expressions involving numeric and string values with the + operator, JavaScript converts numeric values to strings"; its "String Operators" documentation notes that the concatenation of two string values returns another string.) The string "var1" is then evaluated by the eval( ) function to give pic1.gif, which is assigned to the src attribute of the image placeholder as in the first answer script. (The strings "var2" and "var3" are similarly evaluated to pic2.gif and pic3.gif, respectively.)

Thus does the eval( ) function coordinate (a) the random number num, (b) the var# identifiers, which now do serve as an index, and (c) the pic#.gif image files. Clever indeed, but not something that a Weekend Silicon Warrior such as myself would come up with.

Now, perhaps you are thinking to yourself, "The use of the eval( ) function in the Primer #22 Script was redundant; what happens if we remove it here?" Good question. Again, suppose that num = 1. The command:

document.write("<img src=' " + "var"+num +" '>");

assigns the string "var1" to the image src attribute. With respect to the script, "var1", in contrast to "pic1.gif", is not an image file name. Result: no image loads, although no errors are thrown. FYI, the command:

document.write("<img src=' " + var+num +" '>");

throws a syntax error with both MSIE and Netscape.

However, what we can do is write the image with the following eval( )-less command:

document.write("<img src='pic" + num + ".gif'>");

Noteworthily, this command renders unnecessary the var#="pic#.gif" statements at the beginning of the script.

Finally, my I-don't-want-to-reload script above is easily retooled for displaying a random image. Try it out below:




....describes my mood today.
Click here for the code.

We will certainly encounter more uses of if...else statements in future scripts. Meanwhile, in the next two posts we'll switch gears and take up JavaScript looping techniques, beginning with a discussion of for loops in Primer #24.

reptile7

Tuesday, May 09, 2006
 
Good Grief, More If...else
Blog Entry #38

We continue our if...else odyssey with a dissection of HTML Goodies' JavaScript Primers #22, "IF/ELSE Statements." Remember Primer #20's random number script? You know, the script that displayed a Date object-derived random number on an alert( ) box upon clicking a form button? Ah, good - Primer #22 brings back the Primer #20 Script, but with a twist: today, we'll use an if...else statement to turn this script into a guessing game that will "allow you to take pot shots [at the random number] until you get the number right," quoting Joe in the "Deconstructing the Script" section of Primer #22. With no further ado, let's put the Primer #22 Script in the crosshairs:

<html><head>
<script type="text/javascript">
function rand( ) {
now=new Date( );
num=(now.getSeconds( ))%10;
num=num+1; }
function guessnum( ) {
guess=prompt("Your guess?");
if (eval(guess) == num) {
alert("YOU GUESSED IT!!");
rand( ); }
else
alert("No. Try again."); }
</script></head>
<body onLoad="rand( );">
<h2>I'm thinking of a number from 1 to 10</h1>
<form name="myform">
<input type="button" value="Guess" name="b1" onClick="guessnum( );">
</form></body></html>

Alas, Joe's script demo does not work; however, the folks at Hope College's Computer Science Department have mirrored Primer #22 here, with a functional "The Script's Effect" page here.

We can break down the Primer #22 Script into three parts:

(1) The document head's rand( ) function, which is almost identical to the rand( ) function in the Primer #20 Script (not the Primer #21 Script, as incorrectly stated in the primer). Primer #20's rand( ) commands were discussed in detail in Blog Entry #36, so there's no need to rehash them here - we'll see below that these commands can be 'unfunctionized' (i.e., they don't need to be in a function) if desired;

(2) The document head's guessnum( ) function, which we'll take up shortly; and

(3) The document body HTML, which largely parallels the corresponding document body code of the last two primer scripts. (In case you were wondering, the "I'm thinking of a number from 1 to 10" header is uneventfully rendered as an h2 element by both MSIE and Netscape in spite of the mismatched closing </h1> tag, as can be shown at the aforelinked Hope College demo site, which does not bother to correct the mismatch.)

The guessnum( ) function

Let's set the stage, shall we? When the document loads, we first generate a random number num whose value runs from 1 to 10 via the rand( ) function, which is triggered by the onLoad event handler in the document <body> tag. We're now ready to guess what that random number is, and we accordingly click the "Guess [the number]" button, which triggers the guessnum( ) function.

Up pops a prompt( ) box that asks, "Your guess?" The user types in a number, which is assigned to the variable guess after the "OK" button is clicked. This brings us to the script's central if...else statement:

if (eval(guess) == num)
{alert("YOU GUESSED IT!!"); rand( );}
else
alert("No. Try again.");

The if code is executed if the user guesses the random number correctly; for an incorrect guess, the else code is executed.

Without any comment at all on Joe's part, the if conditional statement invokes the top-level eval( ) function, whose purpose here is to ensure that guess is interpreted as a number data type and not as a string data type (recall from the previous post that prompt( ) outputs are strings). The eval( ) function evaluates code in the form of a string; for example, eval("31%10") would return 1, and with respect to the Primer #22 Script, eval("document.myform.b1.type") would return button.

(There's no mention of the eval( ) function on Primer #22's "What You've Learned" page, but it does at least appear in the HTML Goodies JavaScript methods keyword reference.)

As noted in Netscape's eval( ) documentation, the eval( ) function evaluates numerical string literals to give their number equivalents. So, getting back to our guessing game, suppose the user types 5 into the prompt( ) box; 5 is outputted/assigned to guess as a string (i.e., it's now "5"), and then eval(guess)=eval("5") reconverts "5" to 5, the number.

The if statement then compares the eval(guess) return with the value of num from the rand( ) function to see if they are equal; this comparison raises a few interesting-if-not-quite-crucial issues:

(1) With respect to variable scope, both the now and num variables are initialized inside of the rand( ) function and thus qualify as local (not global) variables; before the fact, then, one might expect the guessnum( ) function to not recognize num and perhaps throw an error at this point, and yet it is clear that num undergoes 'function crossing' without any problems, as you can see for yourself at the Hope College demo page.

(2) Netscape's "Variable Scope" documentation also states, "[Y]ou must use var to declare a variable inside a function." Neither now, num, nor guess is declared via the var keyword, but this again poses no problems vis-à-vis the script's effect. (Looking back, I see that the assignment answer scripts for Primers #14, #20, and #21 also feature local variables that are not declared with var.)

(3) If we're going to use the == equal comparison operator here, then use of the eval( ) function is in fact not necessary. According to Netscape's "Comparison Operators" documentation: "The standard equality operators (== and !=) compare two operands without regard to their type...When type conversion is needed, JavaScript converts String, Number, Boolean, or Object operands as follows[:] When comparing a number and a string, the string is converted to a number value." It follows that in the eval( )-less statement:

if (guess == num) {alert("YOU GUESSED IT!!"); rand( );}

the browser's JavaScript engine will automatically convert guess to a number, so no 'evaluation' of guess is required.

(The preceding Netscape reference notes that JavaScript also has a === "strict equal" binary comparison operator that returns true only if its operands are equal and of the same type; the use of === in guessnum( )'s if statement:

if (eval(guess) === num) {alert("YOU GUESSED IT!!"); rand( );}

would indeed require the eval( ) function to convert guess to a number.)

Anyway, if eval(guess) and num are equal, then the if alert( ) box pops up announcing "YOU GUESSED IT!!", followed by a rand( ) function call, which Joe does not discuss and which generates a new random number if the user wants another go at the game. As far as I am aware, this is the first time in the HTML Goodies JavaScript Primers series that a function is called via a basic function_name( ) command (as opposed to using an event handler).

If eval(guess) and num are not equal, then the else alert( ) box pops up announcing "No. Try again." To make subsequent guesses, the user reclicks the "Guess [the number]" button and the guessnum( ) process starts all over again.

Note that alert("No. Try again."); is not surrounded by braces, which can be omitted for a solitary if or else command.

Other code possibilities

As noted above, the random number code does not need to be functionized. Consider, for example, the following script:

<head><script type="text/javascript">
now=new Date( ); num=(now.getSeconds( ))%10; num=num+1;
function guessnum2( ) {
var guess=prompt("Your guess?");
if (guess == num) {alert("YOU GUESSED IT!!"); history.go(0);}
else {alert("No. Try again."); guessnum2( );} }
</script></head>
<body><h2>I'm thinking of a number from 1 to 10</h2>
<form><input type="button" value="Guess the number" onclick="guessnum2( );">
</form></body>

Try it out:


After a first play of the game, the random number is refreshed by reloading the page via a history.go(0) command in the if code. I've also included a guessnum2( ) function call* in the else code - this sets up a prompt( )-alert( ) loop** for incorrect guesses so that you don't need to click the "Guess the number" button over and over.
(*Netscape's "Calling Functions" documentation notes, "A function can...be recursive, that is, it can call itself.")
(**I recognize that some users might find this annoying; the else guessnum2( ) function call can be left out if desired.)

Relatedly, the random number code can alternatively be brought into the guessnum( ) function if, again, guessnum( ) includes a looping mechanism that bypasses the random number code; for example:

<head><script type="text/javascript">
function guessnum3( ) {
now=new Date( ); num=(now.getSeconds( ))%10; num=num+1;
guess=prompt("Your guess?");
if (guess == num) {alert("YOU GUESSED IT!!");}
while (guess != num) {
alert("No. Try again.");
guess=prompt("Your guess?");
if (guess == num) {alert("YOU GUESSED IT!!");} } }
</script></head>
<body><h2>I'm thinking of a number from 1 to 10</h2>
<form><input type="button" value="Guess the number" onclick="guessnum3( );">
</form></body>

The script above uses a while loop to handle incorrect guesses:

while (guess != num) {
alert("No. Try again.");
guess=prompt("Your guess?");
if (guess == num) {alert("YOU GUESSED IT!!");} }

The while loop code says, "As long as guess is not equal to num [!= is the 'not equal' comparison operator], then execute the following code in {braces} repeatedly, but if guess becomes equal to num, then stop"; note that the browser skips over the loop's if statement if guess is not equal to num. We will revisit the while loop topic when we discuss Primer #25.

The Primer #22 Assignment

In the Primer #22 Assignment, Joe asks the reader to modify the Primer #22 Script so that it indicates whether the user's guess at the random number is too high, too low, or just right. Towards this end, the assignment answer script employs in a corresponding guessnum( ) function a series of if statements making use of the ==, > (is greater than), and < (is less than) comparison operators:

function guessnum( ) {
guess=prompt("What is your guess?");
if (eval(guess) == num) // if statement #1
{alert("YOU GUESSED MY NUMBER!!");}
if (eval(guess) > num) // if statement #2
{alert("Too high! Press the button to guess again.")}
if (eval(guess) < num) // if statement #3
{alert("Too low! Press the button to guess again.")} }

In none of the if statements above is the eval( ) function actually necessary to convert guess to a number; > and < comparisons are like == comparisons in this regard.

Significantly, note that if statement #1 (the "just right" comparison) does not have a rand( ) function call for renewing the random number num, and there's a reason for this: if it did include a rand( ); command, then when the user guesses correctly, the "YOU GUESSED MY NUMBER!!" alert( ) message will in most cases be followed by either a "Too high!" or a "Too low!" alert( ) message. Bear in mind that even if if statement #1's condition is true, the browser isn't finished with the guessnum( ) function and is still going to check if statements #2 and #3. Evidently and somewhat unintuitively, a rand( ) function call in if statement #1 creates a new random number num, ready for use, before the browser acts on if statement #2, and if the new num is different than the old num, then either if statement #2's condition or if statement #3's condition will be true, resulting in a second alert( ) message.

There are at least three simple workarounds for this problem:
(1) Renew the random number num with a history.go(0) command in if statement #1, as in the guessnum2( ) function above;
(2) Put a rand( ) function call in if statement #1 but delay its execution via the setTimeout( ) method of the window object, e.g., window.setTimeout("rand( )",2000); or
(3) Reorder the guessnum( ) if statements, putting the "just right" comparison last.

Finally, the assignment does make a useful larger point: a 'multiple-choice' script leading to three or more outcomes can often be crafted with a set of if statements and without any else statements.

We'll conclude our if...else series in the next post with a discussion of HTML Goodies' JavaScript Primers #23, in which we'll use if...else statements to display random text strings and images.

reptile7


Powered by Blogger

Actually, reptile7's JavaScript blog is powered by Café La Llave. ;-)