User-defined Functions


Goal

By the end of today, you will be able to:

  1. use the appropriate vocabulary to talk about functions
  2. define functions with parameters
  3. define functions that return a value
  4. understand the difference between local and global variables

Recap

Three metaphors:

  • Function as a recipe: named textual procedure. Can be defined and made later.
  • Function as a machine: can have inputs and outputs and effects. Can be created and used later.
  • Function as a workspace: can have its own local storage, distinct from other storage.

A function allows us to package up a chunk of code and give it a name. We can run that code later by invoking (or calling) the function.

We define a function like this:

    function name_of_function () {
        // body of function
    }

    function yo () {
        alert("Hey there!");
    }
  

We invoke a function using its name and parens:

 yo(); 

Functions with Parameters and Arguments

Using parameters, we can make functions that are more powerful and general.

  • They can handle a broader set of situations by taking arguments.
  • Inside the function definition, the name given to an argument is parameter (but we won't be pedantic about this).
  • Parameters only exist inside the function. They don't exist outside it. They live and die during one function execution. This is a good thing.
  • Local variables of a function should be declared with var. This makes them like parameters, in the sense that they exist only inside the function and only when the function is executing.
  • Functions can also return values to their caller. Think of this as the answer to a question that the caller has asked. This is a good thing.
  • A picture can help your understanding of this.
  • Variables that are visible and usable in every function are called global. Variables that are visible and usable only in one function are called local. This is their scope.
  • Local variables are better because they minimize the chance that one value will step on or overwrite another. Imagine the following, which actually happened in a computer graphics program I once wrote:
    tan = Math.sin(angle)/Math.cos(angle);  // compute tangent of angle
    
    tan = "#FFCC99";     // store a shade of tan 
    
  • We can describe functions in terms of:
    • return values: some functions return values
    • side effects: something that the function does rather than something it returns. For example, the yo function above does not return a value, but it does cause an alert to happen. That's its side-effect.
  • Functions can have return values or side-effects or both. A function that does neither would be useless.
  • Functions can be treated as values, such as being stored in variable or passed as arguments to functions.

The "Who am I?" game

A bunch of JavaScript attendees, in full costume, are playing a party game, “Who am I?” They give you a clue, and you try to guess who they are, based on what they say. Assume they always tell the truth about themselves.

Quiz Question Nr. 1a

CLUE: I get passed into a function.

  1. parameter

  2. argument

  3. global variable

  4. local variable

Quiz Question Nr. 1b

CLUE: I am everywhere

  1. parameter

  2. argument

  3. global variable

  4. local variable

Quiz Question Nr. 1c

CLUE: Where I can be seen

  1. return

  2. scope

  3. global variable

  4. local variable

Quiz Question Nr. 2

You are given two alternative definitions of a function:

Definition 1

function displayDate() {               
    var today = new Date();                     
    document.getElementById("date").innerHTML = today.toLocaleDateString();
}

Definition 2

function displayDate(dateStr, elemID) {               
    if(dateStr == "now") {
        var date = new Date();
    } else {
        var date = new Date(dateStr);
    }
    document.getElementById(elemID).innerHTML = date.toLocaleDateString();
}

Which of the following statements is true? Explain your answer.

  1. The two definitions are equivalent.

  2. Definition 1 is better than Definition 2.

  3. Definition 2 is better than Definition 1.

  4. Definition 2 is longer than Definition 1.

Given definition 2, how can we display the current date? The date for Valentine's day? How would we do those for definition 1?

Quiz Question Nr. 3

Which of the following function/method calls causes a side effect instead of returning a value.

  1. parseInt()
    
  2. prompt("Enter your name:")
    
  3. document.getElementById("fred")
    
  4. alert("Hello")
    

Quiz Question Nr. 4

What is the effect of executing the following code:


/* a and b are the lengths of two adjacent sides of triangle, and
angle is the number of degrees between them. */

function isEquilateral(a, b, angle) { 
    if (a == b && angle == 60) 
        return true;
}

alert(isEquilateral(10,10,90));
  1. true
    
  2. false
    
  3. NaN
    
  4. undefined
    

The point is that if a function is supposed to return a value, it should probably always return a value (unless some kind of error has occurred or some unusual situation). Above, the isEquilateral function should answer the question is this a square and so it should always answer true or false and therefore always return a boolean.

Scope

Recall that scope tells us where a variable exists and can be used. Variables that usable in every function are called global. Variables that are usable only in one function are called local.

Quiz Question Nr. 5

What is the result of the following statements?

// ======================================================
// generally useful function
function amountToPay(subtotal){
    var total = subtotal + 0.0625 * subtotal;  // add state tax
    return total;
}

// ======================================================
// problem-specific code

var restaurantBill = 100;

amountToPay(restaurantBill);
console.log(restaurantBill);
  1. 100
    
  2. 106.25
    

Note the difference between the global variable restaurantBill and the parameter subtotal. The parameter is generic, since the function could be used in a wide variety of situations. The global is particular to a situation. We might also have globals like gymCharge and barTab, keeping track of different parts of our spending.

Note also that the name for the global and the name for the local are unrelated. It's a common misconception that they must be the same.

One important point about the code above is that if a function returns a value, the caller should almost always receive and use that value. Of course, the function might also have a side-effect which is the reason it's being called.

If it doesn't have a side-effect, and the return value is being ignored, the function invocation is useless.

Exercise 1: General Tax Rate

Define a function named amountToPay2, based on the amountToPay function from the last quiz question to include a second parameter that is the state tax rate, so that it can calculate the amount to pay depending on a buyer's state. You can invoke the function a few times to test it, like this:

alert(amountToPay2(100, 4.0));   // NY tax
alert(amountToPay2(100, 7.5));   // CA tax

Your solution might look like this:

function amountToPay2(subtotal, stateRate) {
    var total = subtotal + (stateRate/100) * subtotal;             // add state tax
    return total;
}

// ========================================================

alert(amountToPay2(100, 4.0));   // NY tax
alert(amountToPay2(100, 7.5));   // CA tax
  

Making Functions More General

The trick we just saw makes the function more general by replacing a constant in the code with a parameter, and then requiring the caller to supply the value. This then gives the caller the freedom to provide other values. The amountToPay2 function can do everything that the amountToPay function does, plus a lot more. After all, the original function only worked for Massachusetts; the revision works for all 50 states, plus the District of Columbia.

Replacing constants with parameters is a pretty common technique; keep it in mind.

Making Functions More Specific

Of course, the general function is a bit less convenient, because you have to supply the tax rate (and maybe you don't even know it!). Suppose we only had the general function and we wanted to define the specific version for Massachusetts.

Exercise 2: Massachusetts Tax Rate

Define a function named amountToPayMass, which will invoke the the amountToPay2 function from the last exercise. The new function will only take one argument, the pre-tax bill and it will return the amount with Mass state tax added. You can invoke the function a few times to test it, like this:

alert(amountToPayMass(100));
alert(amountToPayMass(200));

Your solution might look like this:

function amountToPay2(subtotal, stateRate){
    var total = subtotal + (stateRate/100) * subtotal;             // add state tax
    return total;
}

function amountToPayMass(bill){
    return amountToPay2(bill,6.25);
}

// ========================================================

alert(amountToPayMass(100));
alert(amountToPayMass(200));
  

That may seem surprising, but it's quite reasonable take a general function and make a more specific version just for the use we want to make of it.

More importantly, it's useful to think about the information flow here:

  • The argument, say 100, is given to amountToPayMass
  • That function passes the 100 and the 6.25 down to amountToPay2
  • That function computes the result and returns it to amountToPayMass, and
  • amountToPayMass returns it to the original caller.

It's almost like a bucket brigade.

Hexadecimal -- OPTIONAL

Let's do one last series of examples. I have implemented on this page a function named hexDigit. It takes a number from 0--15 and returns the corresponding digit in hexadecimal, as a string. Here's a demo:


It doesn't work for larger values, so let's build that.

Exercise: hexByte

Define a function named hexByte that takes a number from 0--255 and returns the hexadecimal equivalent as a string. Your function should use the hexDigit function I defined. Here's what the function will need to do:

  1. Accept an input as a parameter. Make up an appropriate name.
  2. Compute the value of the 16s place and the 1s place. One way is to divide the number by 16, taking the Math.floor to get the quotient. Then use the remainder operator to determine the 1s place, or subtract the number of 16s from the input.
  3. Invoke the hexDigit function on each of those values.
  4. Concatenate the results, and
  5. Return the final string.

You can test it like this:

alert(hexByte(15));  // "F"
alert(hexByte(16));  // "10"
alert(hexByte(160));  // "A0"
alert(hexByte(255));  // "FF"

Your solution might look like this:

function hexByte(byte){
    var quo = Math.floor( byte/16 );
    var rem = byte - 16*quo;          // or byte % 16
    return hexDigit(quo)+hexDigit(rem);
}

alert(hexByte(15));  // "0F"
alert(hexByte(16));  // "10"
alert(hexByte(160));  // "A0"
alert(hexByte(255));  // "FF"
  

Exercise: hexColor

Now, let's build on that.

Define a function named hexColor that takes three inputs, an amount of red, green and blue, and returns a hex color specification (a string starting with # and with 6 hex digits like #RRGGBB). Your function should use the hexByte function from the previous exercise. Here's what the function will need to do:

  1. Accept three inputs as parameters. Make up appropriate names.
  2. Invoke the hexByte function on each.
  3. Concatenate the results, and concatenating a # character on the front.
  4. Return the final string.

You can test it like this:

alert(hexColor(0,0,255));     // "#0000FF"
alert(hexColor(128,128,128));  // "#808080"
alert(hexColor(64,128,192));  // "#4080C0"

Your solution might look like this:

function hexByte(byte){
    var quo = Math.floor( byte/16 );
    var rem = byte - 16*quo;          // or byte % 16
    return hexDigit(quo)+hexDigit(rem);
}

function hexColor(r,g,b) {
    return "#"+hexByte(r)+hexByte(g)+hexByte(b);
}

alert(hexColor(0,0,255));     // "#0000FF"
alert(hexColor(128,128,128));  // "#808080"
alert(hexColor(64,128,192));  // "#4080C0"
  

Thank goodness for functions! Think of what a mess that code would be if we didn't have the hexByte function! That function makes the code for hexColor clear, concise and correct.

Demo: setBackgroundColor

Now, let's put that to some use. Try the following function:


Note that this last function does not return a value; instead, it has a side-effect of changing the background color of the page.

In the next few lectures, we'll see how JavaScript can be used to manipulate our web pages, as we saw there.

Summary

We hope that after these activities you have a good understanding of:

  • how to talk about functions and know the meaning of parameter, argument, return, etc.
  • scope, global variables, and local variables
  • define simple functions with parameters
  • define functions that return a value
  • define functions that have a side-effect

Solutions

Will be posted later, visit again after .

Quiz questions:

1a. B  arguments are the values passed in
1b. C  global variables are visible everywhere
1c. B  "scope" is the term for where variables are visible
2. C   The second function does everything the first does, and much more
3. D   B has an effect as well as returning a value, so it does *both*
4. D   undefined, since it doesn't return a value. It should return "false"
5. A   the global variable is unaffected.

Exercise 1:



Exercise 2:



Exercise 3:



Exercise 4: