20 Functions
In the previous chapter you learned how to manipulate the DOM to produce different kinds of output from a JavaScript program. In most cases, you defined a function and then called it later from the console. That’s not a good user interface! In the next chapter, you’ll learn how to trigger functions in response to events like mouse clicks and movements. But before we get there, you need to know a bit more about JavaScript functions.
Functions as Values
JavaScript functions are actually values, just like Strings, Numbers, Booleans, and Objects. Like any other value, functions can be stored in variables, defined within other functions, passed as parameters to other functions, and returned from function calls.
The technical term for this is that JavaScript functions are first-class functions. When you use a function declaration like this…
function sayHi(name) { return "Hello, " + name + "!"; }
… what you are really doing is creating a variable named sayHi, and assigning a function value to it.
JavaScript also supports another style of function declaration that makes this explicit:
let sayHi = function(name) { return "Hello, " + name + "!"; };
The above statement creates a variable named sayHi, and assigns to it an anonymous function with 3 parameters. (Note that since the statement above is an assignment statement, we put a semicolon at the end of it.) The function being assigned is called an anonymous function because it is created without being given a name. The “name” used to call it is the variable name it’s assigned to.
Anonymous functions are also referred to as function literals because, like Number, String, or Array literals, they are values that are hard-coded into the program.
The main difference between the two function declaration notations is that you can only use function declaration in certain contexts, but you can use variable declaration and anonymous functions in any context. In fact, the function declaration notation is avoided by some JavaScript programmers on the grounds that it is limited in use and adds nothing to the language.
Connections
In Java, methods and variables are completely different entities. (Question: how would you describe this difference?)
In Python, functions are first class just like in Javascript. Function names in Python have the same status as variable names.
JavaScript also supports arrow functions, which provide a much more compact syntax for defining anonymous functions. We will discuss arrow functions later, but if you want to learn about them now, try W3School’s JS Arrow Function.
Do it Yourself
No matter whether you use function declaration or variable declaration with anonymous functions, if you refer to a function name in your program, you are referring to a variable. To see this, try the following in the JavaScript console of your browser and see if you can make sense of the results:
function foo () {alert("hi");} // foo is a function foo; foo(); alert(foo); alert(foo());
In the console window, foo returns the value of the variable. It’s a function. But foo() calls the function so you will see the popup. On the other hand, alert(foo) will display a popup whose content is the value of the variable foo (if it’s a function, it will show you something to that effect). Finally, alert(foo()) will first call the foo function, displaying a popup. Then it will create another popup to display the return value of foo. Since there is nothing explicitly returned, it will display the special value undefined.
Try the lines below to see that you can switch foo back and forth between a function and other data types.
foo = 5; // foo is now a number alert(foo); foo = function() {alert("hi again");}; // foo is a function again alert(foo); foo = "hi"; // foo is now a string alert(foo);
Functions as Arguments
Since functions are values, they can be used as arguments to other functions. In the example below, the function doSomething is expecting another function to be passed to it as an argument. It’s job is to call that function.
function doSomething(f, a) { return f(a); }
You could call doSomething and pass it the sayHi function from a previous chapter as its first parameter.
function sayHi(name) { alert("Hello "+name+"!"); }
doSomething(sayHi, "Serena");
You could also pass it an anonymous function for its first argument. This looks a little strange if you’ve never seen anything like it before.
doSomething(function(x) {
return Math.floor(Math.random()*x);
}, 34);
The first parameter to doSomething in the example above is the entire function literal in blue. The second parameter is the value 34. Note the closing brackets and semicolon at the end of the statement. This kind of code structure might take some getting used to, but it’s very common in the world of JavaScript programming.
Do it Yourself
Try the following in a console or script element:
let sayHi = function() {console.log("hello")}; setTimout(sayHi, 1000);
The built-in setTimeout function takes two parameters: a function f and an integer d. Then it calls f after d milliseconds.
Now try this:
setInterval(function() { console.log("hi") }, 500)
The setInterval function takes the same parameters as setTimeout but it will continue to call f every d milliseconds after the first call. In the example above, the first parameter is an anonymous function rather than a variable containing a function.
(Both functions return an integer id that can be sent as an argument to the clearTimeout function to stop the timer.)
Both these functions are useful in user interface design and we will return to them later. See The JS Timing section of W3Schools for more information.
Functions as Local Variables
Because functions are values, we can declare local functions inside other functions.
function outerFunction(a, b, c = 0) { console.log("outerFunction called"); function innerFunction(a, b) { console.log("innerFunction called"); return a * b; }; return innerFunction(b, c) + innerFunction(a, c); }
In the example above, the blue function is declared inside another function. The name innerFunction becomes a local variable of outerFunction.
Do it Yourself
Paste the code for outerFunction above example into the console or a script element. Then in the console, try to predict the output and the return value of the following:
outerFunction(2, 5); outerFunction(2, 5, 2);
Did you get it right?
<exercises chapter=”functions”>
- Create two JavaScript functions called heads and tails using the let syntax. These functions should use console.log to output “heads” and “tails” respectively. Now create a JavaScript function called switch that accepts three arguments: two functions and a number between 0 and 1. If the number is less than 0.5, call the first function. Otherwise, call the second function. Now test your function by calling it 10 times passing the heads and tails functions as arguments. The third argument should be Math.random().
- This exercise is about timing functions.
- In a script element on a web page, declare a global counter variable and a function that increases the counter by 1 and prints it to the console every time it is called. Then use the built in JavaScript function setInterval to call the function you wrote once per second.
- Use setInterval together with setTimeout and other function declarations so that 5 seconds after the page is loaded, integers start appearing in the console, starting at 2 and then increasing by 2 every quarter of a second.
- The clearTimeout function can be used to cancel the operation of setTimeout or setInterval. Both setTimeout and setInterval return a timer ID. Then clearTimout will accept a timer ID and stop that timer. Use setTimeout and clearTimout in the script from the last question so that the counting ends after 5 seconds.
- Wrap all the code you wrote above into a startTimer function so that all the functions and variables you were using become local to the startTimer function. Then load the page, and call startTimer from the console.