Team LiB
Previous Section Next Section

Chapter 4: JavaScript Functions

A function is a collection of one or more script statements that can be made to run at any point during the life of a program. The true power of JavaScript lies in the ability it gives you to write and use user-defined functions. Functions allow you to write very compact, easy-to-understand, and reusable code. Without functions, you'd only be able to write very simple, very lengthy programs. In Chapter 3, I presented many examples of functions without giving you much explanation as to how they work. In this chapter, you'll explore, and I'll explain, every aspect of user-defined functions, as well as JavaScript's built-in, or top-level, functions.

Defining Functions

Declaring functions is just like declaring data of any other type. Here is the syntax:

function <identifier>( <parameter list> )
{
  <statements>
}

The function keyword is followed by an identifier that is the name of the function. The identifier is followed by a comma-separated parameter list enclosed in parentheses. The function body, which can consist of any legal JavaScript statements, is enclosed in curly braces. Unlike with the if and for statements, the curly braces surrounding the function body are required. Following are a couple of examples of functions that you have seen in previous chapters:

       function getColor()
       {
         var color;
         if( rowNumber > 2 )
           rowNumber = 1;

         if( rowNumber == 1 )
           color = "gray";
         else
           color = "white";

         rowNumber++;
         return( color );
       }

This function, named getColor, takes zero parameters. It performs several calculations in its body and then returns a color name. The return statement in this function is common to many functions. When the return statement is reached, the function is exited and the value used as a parameter to the return statement is passed back to the portion of the program that called the function. If no return statement is included in the body of the function, execution is returned to the calling statement as soon as the last statement in the body of the function is done executing. For example, the following statement:

document.write( getColor() );

will print either the string "gray" or "white", depending on the results of the calculations performed within the function body. In another previous example,


function toBinary( n )
{
  var answer = "";
  while( n != 0 )
  {
    answer = Math.abs(n % 2) + answer;
    n = parseInt( n / 2 );
  }
  if( answer.length == 0 ) answer = "0";
  return( answer );
}

the function toBinary() takes a single parameter, which it assumes is an integer, and returns the binary representation of that number. In the following, final example:

function insertAt( index, value )
{
  var part1 = this.slice( 0, index );
  var part2 = this.slice( index );
  part1.push( value );
  return( part1.concat( part2 ) ); 
}

the function insertAt() takes two parameters. It assumes that the first parameter is an integer number and that the second can be any valid JavaScript value. This function inserts the specified value into a preexisting array (this) and returns the results.

As you can see, functions can perform a variety of roles and can perform a vast number of operations.

Recursive Functions

Recursive functions are used very often in computer science. A recursive function is a function that, during the course of executing the statements in its body, makes a call to itself. The logic behind recursive functions is often very complex, but the functions themselves are generally quite simple.

It is important to remember than any function written with a recursive algorithm can also be written with sequential functions. There is a trade-off for using recursive functions instead of sequential functions, however. Recursive functions tend to be faster and require less code, but they require more complex logic and quite a bit more memory to run. Following is an example of a binary sort routine for strings:


<html>
    
  <head>
    <title>
      JavaScript Professional Projects - Recursive Functions
    </title>
          
    <script language="JavaScript">
    <!--
      var months = new Array( "January", "February", "March",
                                "April", "June", "July",
                                "August", "September", "October",
                                "November", "December" );

      function display()
      {
        for( i = 0 ; i < this.length ; i++ )
        {
          document.write( this[i] + "<br>" );
        }
      }
      Array.prototype.display = display;

      function sort( s )
      {
        if( s.length == 1 ) return;
        else
        {
          var a = new Array( parseInt( s.length / 2 ) );
          var b = new Array( s.length a.length );

          for( i = 0 ; i < a.length ; i++ ) a[i] = s[i];
          for( i = 0 ; i < b.length ; i++ ) b[i] = s[i+a.length]; 
          sort( a ); sort( b );

          var ai = 0, bi = 0, i = 0;
          while( ai < a.length || bi < b.length )
          {

           if( bi >= b.length ) s[i++] = a[ai++];
           else if( ai >= a.length ) s[i++] = b[bi++];
           else if( a[ai].compareTo( b[bi] ) <= 0 ) s[i++] = a[ai++];
           else if( a[ai].compareTo( b[bi] ) > 0 ) s[i++] = b[bi++];
         }
        }
       }

       // <0 - this first
       // =0 - same
       // >0 - s first
       function compareTo( s )
       {
         var len1 = this.length;
         var len2 = s.length;
         var n = ( len1 < len2 ? len1 : len2 );

         for( i = 0 ; i < n ; i++ )
         {
           var a = this.charCodeAt( i );
           var b = s.charCodeAt( i )
           if( a != b )
           {
             return( a - b );
           }
          }
          return( len1 len2 );
        } 
        String.prototype.compareTo = compareTo;
      // -->
      </script>

     </head>

     <body>

       <center>
         <font size=6>JavaScript Professional Projects</font><br>

         <font size=4>Chapter 4: Recursive Functions</font>
       </center>

       <br><br>

       <table border=1 cellspacing="2" cellpadding="20">
         <tr>
           <td width=150><b>Unsorted</b></td>
           <td width="150"><b>Sorted</b></td>
         </tr>
         <tr>
           <td>
             <script language="JavaScript">
             <!--
                  months.display();
             -->
             </script>
           </td>
           <td>
             <script language="JavaScript">
             <!--
                  sort( months );
                  months.display();
             -->
             </script>
           </td>
         </tr>
       </table>

     </body>

</html>

This example makes use of three programmer defined functions. The first function, which extends the Array object's functionality by the use of its prototype property, provides a quick and easy way to display the contents of an array object. Here it is:

function display()
{

   for( i = 0 ; i < this.length ; i++ )
   {
     document.write( this[i] + "<br>" );
   }
}
Array.prototype.display = display;

This function simply iterates through each element in the array (referred to by this) and prints it on its own line.

The third function also extends the functionality of a built-in object type, this time String objects:

function compareTo( s )
{
  var len1 = this.length;
  var len2 = s.length;
  var n = ( len1 < len2 ? len1 : len2 );

  for( i = 0 ; i < n ; i++ )
  {
    var a = this.charCodeAt( i );
    var b = s.charCodeAt( i )
    if( a != b )
    {
      return( a - b );
    }
  }  
  return( len1 - len2 );
}
String.prototype.compareTo = compareTo;

This function compares two strings lexicographically. The comparison is based on the Unicode value of each character in the strings. If there is a difference in either of the strings, a return value that demonstrates that difference is generated. If the function returns a value less than zero, then this occurs lexicographically before ‘s’; a return value of zero means the strings are identical, and a return value that is greater than zero means ‘s’ occurs lexicographically before this. The compareTo() function is very important when it comes to the recursive binary sort function:

function sort( s )
{

 if( s.length == 1 ) return;
 else
 {
   var a = new Array( parseInt( s.length / 2 ) );
   var b = new Array( s.length a.length );

   for( i = 0 ; i < a.length ; i++ ) a[i] = s[i];
   for( i = 0 ; i < b.length ; i++ ) b[i] = s[i+a.length];

   sort( a );
   sort( b );
  
   var ai = 0, bi = 0, i = 0;
   while( ai < a.length || bi < b.length )
   {
     if( bi >= b.length ) s[i++] = a[ai++];
     else if( ai >= a.length ) s[i++] = b[bi++];
     else if( a[ai].compareTo( b[bi] ) <= 0 ) s[i++] = a[ai++];
     else if( a[ai].compareTo( b[bi] ) > 0 ) s[i++] = b[bi++];
   }
  }
}

There are two important parts to this function: the base case and the actual body. The base case in this example is

if( s.length == 1 ) return;

Every recursive function must have a base case. In this binary sort function, the base case is when the length of the array is equal to one. You might be wondering how that could occur— that will be explained shortly.

The second part of the recursive function, the body (which is inside the else block), in this case divides the array into roughly equal halves, calls itself with the array halves as arguments, and then reinserts the array halves back into the original array in alphabetical order.

When designing recursive algorithms, it is helpful to think of them as loops. Just as with loops, your recursive functions can sometimes become infinite. The recursive base case is similar to the condition statement in repetition structures—it must always provide a way for the process to end. In many cases, the recursive base case is as simple as the example above, providing no additional functionality, only a return statement.


Team LiB
Previous Section Next Section