reptile7's JavaScript blog
Friday, April 28, 2006
 
More on If...else Statements
Blog Entry #37

(In the text of today's entry, we continue our adventures in syntactical color-coding: all references to if...else statements appear in green, whereas all references to variable identifiers appear in red as they did in the previous post.)

HTML Goodies' JavaScript Primers #13 and Blog Entry #28 introduced us to if...else statements in the context of a discussion of the confirm( ) method of the window object. To my observation, the confirm( ) method does not crop up all that often in JavaScript scripts, but as for if...else statements, well, that's another story - you see these statements used just about everywhere in the JavaScript world, and for good reason. If...else statements add considerable flexibility to a script, transforming it from a mere sequence of commands into a 'contingency plan' that allows the scriptwriter to map out two or more courses of action for a given situation. We return to if...else statements in this and the next two posts, as Primers #21, #22, and #23 compose an if...else 'primer trilogy' of sorts, presenting a series of scripts that do simple-yet-fun things courtesy of if...else statements.

Primer #21, "Introduction to IF and Branching," appropriately kicks off our if...else festival; its focal script, which engages the user in a 'conversation' on sports, appears below:

<html><head>
<script type="text/javascript">
function askuser( ) {
var answer="   "; // function command #1
var statement="Answer yes or no"; // function command #2
var answer=prompt("Do you like sports?"); // function command #3
if (answer == "yes") // if statement #1
{statement="I like sports too!";}
if (answer == "no") // if statement #2
{statement="I hate sports too!";}
alert(statement); } // function command #4
</script></head>
<body>
<h1>Activities</h1>
<form action="">
<input type="button" value="click me" onClick="askuser( );">
</form></body></html>

The if...else action occurs in the askuser( ) function in the document head. Note that the script does not have an else part, which Joe circumvents by a careful ordering of commands; recall from Blog Entry #28 that the else part of an if...else statement is in fact optional. However, we'll see below that the script can have an else part if desired.

Let's begin our deconstruction with askuser( )'s function command #3, which pops up a prompt( ) box asking the age-old question, "Do you like sports?" The user types in a response, which is assigned to the variable answer after the "OK" button is clicked. The script is set up to handle three possibilities:

(1) If the user types in "yes" - all in lowercase letters - then if statement #1 kicks in:

if (answer == "yes") {statement="I like sports too!";}

The conditional expression in parentheses, answer == "yes", utilizes the == equal comparison operator. In effect, if statement #1 says, "Is it true that the value of answer is equal to "yes"? If this condition is met [as it is in this case], then assign the text string "I like sports too!" to the variable statement." Subsequently, function command #4 displays statement on an alert( ) box.

Recall from Blog Entry #30 that in JavaScript a single equals sign (=) is an assignment operator that actively assigns the value of its right operand to its left operand. With respect to if statement #1's condition, we're not assigning anything, specifically, we're not assigning "yes" to answer, whose value is set by the prompt( ) command; rather, we are comparing answer and "yes" to see if they are equal, with the == operator returning true if they are and false if they aren't. So, in summary and at the risk of belaboring the obvious, assignment and comparison are two different operations requiring two different operators. Netscape's if...else documentation, linked above, notes that it's possible to have (x = y) assignment statements in if conditional expressions, but that such situations are the exception and not the rule.

(2) If the user answers "no", again all in lowercase letters, then if statement #1's condition returns false, so the browser skips over {statement="I like sports too!";} and moves on to if statement #2:

if (answer == "no") {statement="I hate sports too!";}

If statement #2's condition now returns true, so "I hate sports too!" is assigned to statement, which is again via function command #4 displayed on an alert( ) box. Analogously, the browser skips over {statement="I hate sports too!";} when the user answers "yes", because in this case if statement #2's condition returns false.

(3) For all other responses - including leaving the prompt( ) input field blank and/or clicking the "Cancel" button - the value of statement is set near the beginning of the script by function command #2:

var statement="Answer yes or no";

If the user answers "yes" (if statement #1's condition is true), then {statement="I like sports too!";} overwrites function command #2, and you see "I like sports too!" on the alert( ) box; similarly, if the user answers "no" (if statement #2's condition is true), then {statement="I hate sports too!";} overwrites function command #2, and you see "I hate sports too!" on the alert( ) box. For all other answers ("empty" or otherwise), the conditions of if statements #1 and #2 are both false, and you see "Answer yes or no" on the alert( ) box. Very logical.

As should be clear, the code sequence is important here; had Joe placed the var statement="Answer yes or no" catch-all after if statement #2 (i.e., just before function command #4), then var statement="Answer yes or no" would overwrite {statement="I like sports too!";} or {statement="I hate sports too!";} for the answers "yes" or "no", respectively, and you'd see "Answer yes or no" on the alert( ) box in all cases.

Before moving on, a quick comment on function command #1: somewhat mystifyingly, Joe begins the askuser( ) function by assigning three blank spaces to the answer variable in its initial declaration; "[t]hat empty space will be filled with what the user enters into the prompt box," Joe tells us in the "Deconstructing the Script" section of the primer. Perhaps you are thinking to yourself, "I'll bet we can delete function command #1 without any problems; the prompt( ) command is going to overwrite those spaces anyway," and you would be correct*. Note that the Primer #21 Assignment's answer script, which is patterned on the Primer #21 Script, does not contain a corresponding answer declaration prior to the prompt( ) command.

(*I myself was wondering if Joe wanted to ensure that answer is interpreted as a string data type - I was reminded of his <SCRIPT>document.write("" +name+ "")</SCRIPT> code in the answer to the Primer #6 Assignment. BTW, I find on my computer that a y=prompt(x,y) output y is indeed interpreted as a string regardless of what I enter (including numbers) into the prompt( ) box.)

Else possibilities

When I first read through Primer #21, I thought, "Why don't we put the 'Answer yes or no' catch-all at the end of the function in an else block of code?" I.e.:

function askuser2( ) {
var answer=prompt("Do you like sports?");
if (answer == "yes") {statement="I like sports too!";} // if statement #1
if (answer == "no") {statement="I hate sports too!";} // if statement #2
else
{statement="Answer yes or no";}
window.alert(statement); }

In practice, the function above, as written, works OK for the "no" and for the anything-but-"yes"-or-"no" answers, but not for the "yes" answer, which gives "Answer yes or no" on the alert( ) box. Evidently, for an if...if...else statement, if if statement #2's condition is false, then the else command(s) will execute, even if if statement #1's condition is true. However, we can easily get around this problem by rolling if statements #1 and #2 into an encompassing if statement as follows:

function askuser3( ) {
var answer=prompt("Do you like sports?");
if ((answer == "yes") || (answer == "no")) // if statement #0
{
if (answer == "yes") {statement="I like sports too!";} // if statement #1
if (answer == "no") {statement="I hate sports too!";} // if statement #2
}
else {var statement="Answer yes or no.";}
alert(statement); }

In the code above, if statements #1 and #2 are nested in the outer if statement #0, whose condition, ((answer == "yes") || (answer == "no")), features the double-vertical bar (||) logical/Boolean OR operator, which returns true if either of its operands, (answer == "yes") and (answer == "no") in this case, are true, and which returns false if both of its operands are false. The askuser3( ) function faithfully duplicates the effect of the Primer #21 Script for all possible answers; it's a bit more complicated than the askuser( ) function but reads more straightforwardly, IMO.

Answer case-sensitivity

At the end of his deconstruction, Joe emphasizes, "Remember that JavaScript is case-sensitive. Thus if you type YES or Yes, the condition will be false! You must type yes for the condition to be true." His proposed workaround: "You can fix this by adding more and more IF statements covering all caps or capitalized answers." Yeah, I suppose we could do that, but a much more elegant solution is at hand, namely, we can use the toLowerCase( ) method of the String object to convert uppercased yeas and nays to "yes" and "no", respectively. All we need to do is to follow the var answer=prompt("Do you like sports?") command (in either the askuser( ) function or the askuser3( ) function) with:

answer = answer.toLowerCase( );

and our case-sensitivity problems are solved, with one glitch: clicking the "Cancel" button on the prompt( ) box in this case throws an error (MSIE: "'null' is not an object"; Netscape: "answer has no properties"). (Recall from Blog Entry #11 that canceling a prompt( ) box outputs the null value.) However, after a bit of experimentation, I was able to eliminate this complication with the following code:

function askuser4( ) {
var statement="Answer yes or no.";
var answer=prompt("Do you like sports?");
if (answer == null)
{alert(statement);}
else
{answer = answer.toLowerCase( );
if (answer == "yes") {statement="I like sports too!";}
if (answer == "no") {statement="I hate sports too!";}
alert(statement); } }

Try it out:

In our next episode, we'll take on Primer #22, which uses an if...else statement in a guessing game script.

reptile7

Tuesday, April 18, 2006
 
JavaScript and Random Numbers
Blog Entry #36

As we've seen in numerous examples, JavaScript can be used to controllably modify a document and its body elements on the fly in a variety of ways. Complementarily, we can also use JavaScript to randomly modify a document's content. For example, with JavaScript we can display random text strings (Magic 8-Ball, anyone?) or random images (pop-up/under ads are often random images), or perhaps set up a link that randomly takes the user to one of a collection of Web sites. In today's entry, we'll outline the creation with JavaScript of random numbers, which lie at the heart of the JavaScript randomization of document elements. There are in JavaScript two general approaches for the generation of random numbers:
(1) Via the built-in Date object, as detailed in HTML Goodies' JavaScript Primers #20 ("Creating Random Numbers"); and
(2) Via the built-in Math object, as detailed in JavaScript Kit's "Generating a random number in JavaScript" tutorial.
Both approaches are discussed below.

Random numbers via the Date object

Way back when, Primer #3 introduced us to the JavaScript Date object and several of its methods. In the Primer #20 Script, which follows, Joe uses the getSeconds( ) method of the Date object to generate random numbers:

<html><head>
<script type="text/javascript">
function rand( ) {
var now=new Date( ); // function command #1
var num=(now.getSeconds( ))%10; // function command #2
var num=num+1; // function command #3
alert(num); }
</script></head>
<body>
<h1>Random Numbers</h1>
<form>
<input type="button" value="Random Number from 1 to 10" onClick="rand( );">
</form></body></html>

Joe's murky deconstruction of the Primer #20 Script leaves considerable room for improvement, so your humble narrator will step up to the plate to give you the goods. I trust that I don't need to go over the HTML in the document body, and we'll accordingly zero in on the rand( ) function in the document head.

Function command #1 creates a new instance of the Date object and assigns it to the variable now; we thrashed out the details of Date object constructor statements in Blog Entry #5. (I hate to nitpick but, contra the primer, "new Date( )" is not a method; it's an object.)

Function command #2 is the meat of the script. As Joe notes, the now.getSeconds( ) command is what creates a random number, returning an integer 0 to 59, inclusive, reflecting the seconds count of the current time on your computer. The script then converts the 0-to-59 random number range to a 1-to-10 random number range. We first carry out a modulo operation, a variation of the arithmetic division operation, on the now.getSeconds( ) return. Imagine a division calculation whose quotient is in the form of an integer plus a remainder, e.g.;

45 ÷ 10 = 4 with a remainder of 5

A modulo operation, effected by the % modulo operator, takes the same dividend and divisor, and performs the division, and returns not the quotient but the remainder:

45 % 10 = 5

(I confess that I had never heard of the modulo operation before working through Primer #20 - you learn something new every day! BTW, Netscape terms % the modulus operator. The Latin here seems reversed to me: modulo is the Latin ablative of modulus, and I would think that the operation would be declined in the nominative case (modulus) whereas the operator, as a means or instrument, would be declined in the ablative case (modulo), but Latin is definitely not my area of expertise, so let's just let it be.)
Applying this to function command #2, we obtain:

(now.getSeconds( )) % 10 =
(a random number from 0 to 59) % 10 = a random number from 0 to 9

Whatever random number now.getSeconds( ) happens to be, our choice of 10 for the second operand dictates that the modulo output range will run from 0 to 9, because these are the possible remainders for divisions using 10 as the divisor. Similarly, a %5 operation would return a random number from 0 to 4 as demonstrated in the Primer #20 Assignment, a %20 operation would return a random number from 0 to 19, and so on. (The "%9" at the start of Joe's deconstruction, obviously a typo, would return a random number from 0 to 8.)

Our random number from 0 to 9 is then assigned to the variable num. Note that the modulo operation ensures that num is an integer; had we used a division operation in function command #2 (i.e., var num=(now.getSeconds( ))/10;), then num would range from 0 to 5.9.

One more point before moving on: the outer parentheses surrounding (now.getSeconds( )) are unnecessary and can be left out if desired.

Function command #3 adds 1 to num, converting the 0-to-9 random number range to a 1-to-10 random number range, which is reassigned to num. Finally, num is displayed on an alert( ) box.

Clearly, for the script to return a random or semi-random number, it is necessary to choose a Date object method whose return 'moves along at a good clip,' so to speak; the returns of methods such as getMinutes( ), getHours( ), getDate( ), etc. would change too slowly for our purposes here. On the other hand, there are other Date object methods besides getSeconds( ) that we can use to create random numbers, for example, the getMilliseconds( ) method, which returns an integer 0 to 999, inclusive, again reflecting the seconds count of the current time on your computer; the getTime( ), getUTCSeconds( ), and getUTCMilliseconds( ) methods will also work.

If you've tried out Joe's script demo, clicking the "Random Number from 1 to 10" button several times in quick succession, then you may have noticed that the value of num on the alert( ) box is actually not so random but increases in a semi-regular way (8, 1, 3, 5, 7, 10...) as the getSeconds( ) method tracks the computer clock. The getMilliseconds( ) method moves faster than does the getSeconds( ) method and is thus a better choice for generating a genuinely random number. Try it out:


The code for this is:
<form>
<input type="button" value="Click here for a random number from 1 to 10 via the getMilliseconds( ) method." onclick="var now=new Date( ); var num = now.getMilliseconds( )%10; var num=num+1; window.alert(num);">
</form>

Random numbers via the Math object

Inspired by the JavaScript Kit tutorial linked at the outset of this post, I offer the following sample code for generating a random number from 1 to 10 using the JavaScript Math object:

<script type="text/javascript">
function ranx( ) {
var ran = Math.random( ); // function command A
var ten = ran*10; // function command B
var integ = Math.ceil(ten); // function command C
window.alert(integ); }
</script>
<form>
<input type="button" value="Click here for a random number from 1 and 10." onclick="ranx( );">
</form>

In deconstruction, we turn our attention to the ranx( ) function. You may recall that we discussed the Math object and a number of its methods in Blog Entry #30; in ranx( )'s function command A, we introduce a new Math object method, random( ), which "returns a pseudo-random number between 0 and 1 [based on] the current time," quoting Netscape. The Math.random( ) return, which on my computer runs at least 16 digits past the decimal point, is assigned to the variable ran.

Function command B multiplies ran by 10, converting the between-0-and-1 random number range to a between-0-and-10 (and still running at least 15 digits past the decimal point) random number range, which is assigned to the variable ten.

Function command C introduces new Math object method #2, ceil(x), which rounds up its argument, ten in this case, to the nearest integer, regardless of the digit in the tenths place; this command converts ten's between-0-and-10 noninteger random number range to a 1-to-10 integer random number range, which is assigned to the variable integ, whose value is finally displayed on an alert( ) box.

(An aside: when I wrote this script, I originally assigned the Math.ceil(ten) return to the identifier int, only to find out subsequently that int is a JavaScript reserved word and is thus an unsuitable variable name, as discussed in Blog Entry #30.)

Speaking of the ceil(x) method, the Math object has a corresponding floor(x) method, which rounds down its x argument to the nearest integer, regardless of the digit in the tenths place, and also has a round(x) method, which rounds its x argument up or down to the nearest integer depending on whether x's tenths-place digit is 5-9 or 0-4, respectively. JavaScript Kit makes use of the floor(x) method in its own random number code and argues against the use of the round(x) method, claiming that Math.round(x) gives a less random return than does Math.floor(x). (I'm not sure I buy this, given that just as many tenths-place digits cause Math.round(x) to round up vs. down; indeed, I detected no difference in randomness when I reran my script using var integ = Math.round(ten), which gives a 0-to-10 random number range, for function command C.)

The scripts above can be easily modified to return a variety of random number ranges; it is left to the reader to work out the possibilities therefor. And in this regard, you don't need to limit yourself to a 'Date object script' or a 'Math object script,' as you can profitably mix and match Date and Math object methods within the same random number script, as you might have guessed.

Lastly, advanced readers in the audience might want to check out JavaScript Kit's "Generating weighted random numbers in JavaScript" tutorial, whose inner workings are beyond the scope of this blog entry but which we might examine in a future post.

We'll encounter other applications of Date object- and Math object-based randomization in due course. Meanwhile, in the next few entries, we will revisit and expand on the Primer #13 topic of script branching via if...else statements, beginning with a look at Primer #21.

reptile7

Tuesday, April 04, 2006
 
Form Fields and the Value Property, Part 2
Blog Entry #35

So, I'm looking over HTML Goodies' JavaScript Primers #19 ("Passing Information to the Function"), and I'm thinking to myself, "Are we plowing any new ground here at all?" Maybe a tad. Here's the Primer #19 Script:

<html><head>
<script type="text/javascript">
function doit( ) {
alert("document.myform.fname.value is " + document.myform.fname.value);
var greeting="hello ";
alert(greeting + document.myform.fname.value + " " + document.myform.lname.value);
alert("length of first name " + document.myform.fname.value.length); }
</script></head>
<body>
<form name="myform" action="">
What is your First Name? <input type="text" name="fname"><p>
What is your Last Name? <input type="text" name="lname"><p>
<input type="button" value="Submit" onClick="doit( );">
</form></body></html>

We turn our undivided attention to the script's one new thing (at least with respect to the HTML Goodies JavaScript Primers series), namely, the following hierarchy statement appearing in 'function command #4':

document.myform.fname.value.length

In Primer #7, Joe discussed the length property of the history object, saying, "The property is 'length.' It's a popular one, too. You'll see it used with other commands later on" - well, here we are! We know all about the values of form controls at this point, and as you would expect, the statement above "displays the length of the contents of the fname field. If fname contains 'Joe', the length is 3," to quote Joe from the "Deconstructing the Script" section of the primer. And yet, when I first worked through Primer #19, the syntax of this statement confused me a bit. From the discussion of hierarchy statements in Primer #8, it seemed to me that value is serving here in part as an object; however, in Primer #8 Joe also tells us, "Note that Value and SRC are just Properties!" And he's technically correct in the sense that neither the DOM nor present-day JavaScript features a value element/object.

We now also know, however, that the values of field-type form control objects (i.e., the text, textarea, password, fileUpload, and hidden objects, as listed in Blog Entry #17) do function as de facto JavaScript String objects. We first made this point in Blog Entry #22, whose "The Value Property" section itself sports a document.myform.mytext.value.length statement and, like "The Concept" of Primer #19, makes brief mention of the use of such statements in data entry checking/validation. Subsequently, the "Other 'After-the-Fact' Event Handlers" section of Blog Entry #24 featured a demo that applied the toUpperCase( ) method of the String object to a form field input.

More precisely, a user's input into a field-type control constitutes a string literal, which we defined in Blog Entry #33, and in this regard, Netscape notes, "You can call any of the methods of the String object on a string literal value—JavaScript automatically converts the string literal to a temporary String object, calls the method, then discards the temporary String object. You can also use the String.length property with a string literal." So there you have it.

More generally, we see in DevGuru's JavaScript Properties Index that length is a property of a number of different objects, as Joe implies above (come to think of it, we discussed the length property of the form object in Blog Entry #16); DevGuru's list does not include object collections (images[ ], links[ ], elements[ ], etc.), all of which also have a length property.

Parameterizing the doit( ) function

And that's going to about do it, folks; as you can see, the rest of the Primer #19 Script is a retread of the scripts of earlier primers, and thus needs no 'play-by-play' in this entry - Joe's analysis should suffice as a review if needs be. But I do have one more comment to make. With respect to the doit( ) function call, Joe notes, "No parameters are passed as was done in the two previous primers. [Actually, the Primer #17 Script had a parameterized function, but the Primer #18 Script did not.] We know this because there is nothing in the parentheses ( ) of doit( )." However, we can easily parameterize the doit( ) function if we wanted to; for example:

In the document body, recode the function-call button as:
<input type="button" value="Submit"
onclick="doit(document.myform.fname.value,document.myform.lname.value);">

In the document head, recode the doit( ) function as:
function doit(x,y) {
window.alert("document.myform.fname.value is " + x);
var greeting="hello ";
window.alert(greeting + x + " " + y);
window.alert("length of first name " + x.length); }

IMO, this makes the doit( ) function easier to read, but to each his own, of course.

Its script still features a function and a form, but HTML Goodies' JavaScript Primers #20, which we'll cover in the next post, thankfully moves us into some new territory; specifically, Primer #20 will show how to generate random numbers using JavaScript and the clock running on your computer.

reptile7


Powered by Blogger

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