facebook google plus twitter
Webucator's Free Advanced JavaScript Programming Tutorial

Lesson: Advanced Functions

Welcome to our free Advanced JavaScript Programming tutorial. This tutorial is based on Webucator's Advanced JavaScript Programming course.

We can use features of JavaScript functions to protect private state properties, organize our code, solve difficult challenges more elegantly, and build more flexible and reuseable tools.

Lesson Goals

  • Understand the difference between function declarations and expressions.
  • Create flexible function signatures with default parameters and flexible arguments.
  • Learn how and why to use closures.
  • Learn how and why to use Immediately-Invoked Function Expressions (IFFEs).
  • Learn how and why to use function callbacks.
  • Learn how to write recursive functions.

Function Declarations

Perhaps the most basic manner in which we can create functions in JavaScript is with a function declaration, often called a function statement. It's the way in which most of us first learn about functions and perhaps the most familiar:

function foo(bar) {
	return bar + 3;
}

Here we defined a function named foo which accepts a parameter bar and returns the value of bar plus three. We can call our foo function later

document.write(foo(9));

to write, in the example above, the value 12 to the screen. Because function declarations are hoisted - moved by the JavaScript interpreter to the top of the executing code and evaluated before execution flow - we could even invoke our function foo before declaring it. (This is true for variable declarations in JavaScript, too. Many developers suggest not relying on this feature but rather, for clarity and code organization, declaring variables and functions before they are used.)

Function Expressions

Another way to define a function is with a function expression:

var foo = function(bar) {
	return bar + 3;
}

which we could then call in exactly the same manner as with our function declaration example above:

document.write(foo(9));

Unlike declared functions, function expressions are not hoisted: they are created when the execution flow reaches them. As such, function expressions can be used only after they are defined.

As we'll see later in this lesson, function expressions are useful for closures, as arguments to other functions, and as immediately invoked function expressions (IIFEs). More on this to come.

Let's look at a quick example of the difference between function declarations and function expressions:

Code Sample:

AdvancedFunctions/Demos/functionDeclarationExpression.html
<!DOCTYPE html>
<html>
<head>
	<meta charset="utf-8">
	<title>Function Declarations &amp; Expressions</title>
</head>
<body>
	<h1>Function Declarations &amp; Expressions</h1>
	<script>
		document.write(funDeclaration(10) + ' ');
		function funDeclaration(x) {
			return x + 17;
		}
		document.write(funDeclaration(2));

		document.write('<hr>');
		
		//document.write(funExpression(3) + ' ');
		var funExpression = function(y) {
			return y * y;
		}
		document.write(funExpression(9));
	</script>
</body>
</html>

Code Explanation

Function funDeclaration is a declared function; note that we can call it before or after it is defined, since declared functions are hoisted.

Function funExpression is a function expression. If we were to uncomment the call document.write(funExpression(3) + ' '), which comes before we define function funExpression, we would get an error because function expressions are not hoisted.

Default Values

The ECMAScript 6 ("ES2015") update to JavaScript introduced the default function parameter feature, allowing us to set default values for parameters if they are not supplied when a function is invoked. For instance, a function declared as

function fun(num=2) {
	//code here
}

could be called without a parameter:

document.write(fun());

The function's num parameter would be set to 2, since no value was supplied for the parameter in the function call. Here's another example:

Code Sample:

AdvancedFunctions/Demos/defaultParams.html
<!DOCTYPE html>
<html>
<head>
	<meta charset="utf-8">
	<title>Default Parameters</title>
</head>
<body>
	<h1>Default Parameters</h1>
	<script>
		function fullName(fname='First', lname='Last') {
			return fname + ' ' + lname;
		}
		document.write(fullName('Brian','Hoke'));
		document.write('<hr>');
		document.write(fullName('Brian'));
		document.write('<hr>');
		document.write(fullName());
	</script>
</body>
</html>

Code Explanation

Function fullName accepts two parameters, fname and lname, each of which is assigned a default string value.

We make three calls to the function, supplying two, one, and zero parameters, respectively. Note that, if only one actual parameter is supplied, it is passed in for the first (fname) formal parameter.

Flexible Arguments

JavaScript offers us a way to handle cases where we don't know in advance how many arguments are to be passed to a function. Consider a function which returns an HTML unordered list from a set of strings. We could declare our function to accept an array parameter, loop over the array inside the function to build the unordered list, and return the formatted HTML - but this would require any calling code to first build an array of strings to pass to the function:

var arr = ['item 1', 'item 2', 'item 3'];
document.write(formatAsList(arr));

which would not be as useful as a function that accepts the elements as parameters:

document.write(formatAsList('item 1', 'item 2', 'item 3'));

Of course, we would want the function to accept any arbitrary number of parameters:

document.write(formatAsList('item 1'));
document.write(formatAsList('item 1', 'item 2', 'item 3', 'item 4', 'item 5'));
// etc.

We can't enumerate the parameters in our function definition, even if we used default values for the parameters, because we don't know in advance how many parameters will be passed in the call to our function. Instead, we use the arguments object.

The arguments object is a local variable available within any function. It contains an entry for all of the arguments passed to the function, regardless of whether the function has a formal parameter in its declaration for the passed parameter(s).

A function declared as

function foo(bar) {
	return arguments[1] + ' ' + arguments[2];
}

and called as

document.write(foo('a','b','c'));

would print to the screen the value 'b c', since the arguments object would have three elements ('a', 'b', and 'c') with indices 0, 1, and 2, respectively. Inside function foo, the value of parameter bar and the value of arguments[0] would both be 'a'.

While the arguments object is not an array, we can convert it into an array using Array's from method:

function argsFun1(bar) {
	var myargs = Array.from(arguments);
}
//...
argsFun1('a', 'b', 'c');

or, if we want only a portion of the arguments collection, using Array's slice method:

function argsFun2(bar) {
	var myargs = Array.from(arguments).slice(1);
}
//...
argsFun2('a', 'b', 'c');

In the first example above, the call to argsFun1 would result in the local variable myargs being set to a three-element array with elements 'a', 'b', and 'c' - that is, an Array of all of the passed-in arguments. In the second example above, the call to argsFun2 would set its myargs variable to an Array with two elements, 'b' and 'c', since the slice method returns us the "slice" of the array starting at (and including) the element with index 1.

Thus the following code:

function argsFun1(bar) {
	var myargs = Array.from(arguments);
	console.log('argsFun1: ' + myargs);
}

function argsFun2(bar) {
	var myargs = Array.from(arguments).slice(1);
	console.log('argsFun2: ' + myargs);
}

argsFun1('a', 'b', 'c');
argsFun2('a', 'b', 'c');

would print the following to the console:

argsFun1: a,b,c
argsFun2: b,c

Let's look at an example:

Code Sample:

AdvancedFunctions/Demos/argumentsObject.html
<!DOCTYPE html>
<html>
<head>
	<meta charset="utf-8">
	<title>The arguments Object</title>
</head>
<body>
	<h1>The arguments Object</h1>
	<script>
		function formatAsList(listType) {
			var myargs = Array.from(arguments).slice(1);
			if (myargs.length == 0) {
				return '';
			}
			$html_str = '<' + listType + '>';
			for (var i in myargs) {
				$html_str += '<li>' + myargs[i] + '</li>';
			}
			$html_str += '</' + listType + '>';
			return $html_str;
		}

		document.write(formatAsList('ul','item 1','item 2','item 3'));
		document.write('<hr>');
		document.write(formatAsList('ul'));
		document.write('<hr>');
		document.write(formatAsList('ol','red','green','blue','orange'));
	</script>
</body>
</html>

Code Explanation

Function formatAsList has one formally declared parameter, listType, which expects to receive a value ul (for an unordered list) or ol (for an ordered list).

Function formatAsList first converts its arguments object to an Array (myargs) using the slice method, getting all of the elements except the first (0th) element. If the length of myargs is 0, then the function returns the empty string. If not - that is, if there is at least one parameter to be formatted as an HTML list - then the function builds an HTML string for a list of the specified (ul or ol) type, iterating over the array to build the list items.

The screenshot below shows the output we would get from running the code above:

screenshot of arguments object demo

The first call to formatAsList, on line 23, returns an unordered list with three elements: "item1", "item2", and "item3".

The second call to formatAsList, on line 25, returns the empty string, since there is only one parameter supplied ('ul') and, thus, Array.from(arguments).slice(1) has length zero.

The third call to formatAsList, on line 27, returns an ordered list with four items - the color names.

Flexible Arguments

Duration: 10 to 15 minutes.

In this exercise, you will create a function that finds the maximum or minimum value among an indeterminate number of integer arguments.

  1. Open AdvancedFunctions/Exercises/flexibleArguments.html for editing.
  2. Write the body of function stats which accepts a parameter maxOrMin (a string, with value "max" or "min" to indicate whether to find the maximum or minimum) and accepts an arbitrary number of integer parameters.
  3. Use flexible arguments to allow the function to be called with any number of integers; for instance:
    • stats('max', 3, 49, 20, -3, 17) should return 49
    • stats('min', 22, 11, 38, -3, 17) should return -3
  4. Test your solution in a browser.

Solution:

AdvancedFunctions/Solutions/flexibleArguments.html
<!DOCTYPE html>
<html>
<head>
	<meta charset="utf-8">
	<title>Flexible Arguments</title>
</head>
<body>
	<h1>Flexible Arguments</h1>
	<script>
		function stats(maxOrMin) {
			var myargs = Array.from(arguments).slice(1);
			if (myargs.length == 0) {
				return null;
			}
			if (maxOrMin == 'max') {
				var max = myargs[0];
			} else {
				var min = myargs[0];
			}
			for (var i in myargs) {
				if (maxOrMin == 'max') {
					if (myargs[i] > max) {
						max = myargs[i];
					}
				} else {
					if (myargs[i] < min) {
						min = myargs[i];
					}
				}
			}
			return maxOrMin == 'max' ? max : min;
		}

		document.write(stats('max', 3, 49, 20, -3, 17));
		document.write('<hr>');
		document.write(stats('min', 22, 11, 38, -3, 17));
	</script>
</body>
</html>

Code Explanation

We set local variable myargs to the array of arguments not including the first argument (Array.from(arguments).slice(1)) since the first parameter is the string representing whether we are to find the maxiumum or minimum value.

We set either a temporary max (if maxOrMin is "max") or temporary min, giving the variable the value of the first element in our array of arguments.

We then iterate over the arguments array, setting the current item to be the temporary max or min, as appropriate, and returning the final value.

Closures

Closures in JavaScript are functions that keep reference to properties from their parent-function's scope even after their parent has returned. In our earlier lesson on scope, we learned that a function always has access to variables and parameters from its own scope, from its parent's scope (as with a nested function), and from the global scope. Closures exploit this fact to keep alive the local variables: closures "remember" the environment in which they were created, long after the parent function has finished executing. We can use closures to hide private data and expose structured, protected access to how we want other code to interact with our private data. Let's look at an example:

Code Sample:

AdvancedFunctions/Demos/closures.html
<!DOCTYPE html>
<html>
<head>
	<meta charset="utf-8">
	<title>Closures</title>
</head>
<body>
	<h1>Closures</h1>
	<script>
		function counter(x) {
			return {
				increment: function() {
					x = x + 1;
				},
				get: function() {
					return x;
				}
			}
		};

		var mycounter = counter(3);
		document.write(mycounter.get()); // writes 3
		mycounter.increment();
		mycounter.increment();
		document.write('<br>' + mycounter.get()); // writes 5
		// document.write(x); // this would generate an "x is not defined error"
		x = 14;
		document.write('<br>' + mycounter.get()); // writes 5
	</script>
</body>
</html>

Code Explanation

Function counter accepts a parameter x, expected to be a number, and returns an object with two fields:

  • a function increment, which adds one to parameter x; and
  • a function get, which returns the value of parameter x.

On line 21 we set variable mycounter to counter(3), invoking function counter and passing 3 in for the parameter. We can then call mycounter.get(), to get the current value of x, and mycounter.increment() to increment x by 1.

Why is this useful? That is, why use a closure here? Because it gives us a way to initialize a variable (x, in our case) and allow actions to be performed upon it (increment it, get its current value) but also to protect it from getting or setting other than in the ways in which we want.

If we were to uncomment the code (document.write(x);) on line 26 we would get an error, since x is not defined here: we have protected x from access outside of our function counter.

Setting, on line 27, the value of x has no affect (note that line 28 still writes 5 to the screen), since the assignment on line 27 is defining a different x (one with global scope) which, while it share the same name, is different from the x parameter in our function counter.

Here is another example in which we use closures to create a function generator:

Code Sample:

AdvancedFunctions/Demos/closures2.html
<!DOCTYPE html>
<html>
<head>
	<meta charset="utf-8">
	<title>Closures</title>
</head>
<body>
	<h1>Closures</h1>
	<p>The inner function "remembers" the value of the parameter with which its parent was called:</p>
	<script>
		function add(x){
			return function(y) {
				return x + y;
			};
		}
		
		var add5 = add(5);
		document.write(add5(10));
		document.write('<br>');
		document.write(add5(7));
		document.write('<hr>');

		var add17 = add(17);
		document.write(add17(2));
		document.write('<br>');
		document.write(add17(23));
		document.write('<hr>');
	</script>
</body>
</html>

Code Explanation

Function add accepts a parameter (a number x) and returns an anonymous function, which also accepts a numeric parameter y.

On line 17 we create a variable add5 and assign to it add(5). We can then call add5(10), add5(7), etc. - the number in any of our calls gets passed in for parameter y. The inner function "remembers" the value of x (5, in this case, from our original call to add(5)) and thus we get back the value of 5 plus the number we supply.

Similarly, we can create add17 = add(17) to build a "17 adder", where calls such as add17(2) returns 17 + 2 = 19, 17 + 23 = 40, etc. We have created an "adder function generator" with closures.

In the next exercise, you will use closures to create a basic bank account application:

Closures

Duration: 15 to 25 minutes.

In the simple bank account application you will write in this exercise, you will use closures as a way to maintain state (to keep track of the account balance), to offer external code a way to get and set information (make a deposit or get the current balance), and to protect data (like the balance) from inappropriate tampering.

  1. Open AdvancedFunctions/Exercises/closures.html for editing.
  2. Write the body of function bankAccount as indicated in the comments:
    • Add local variables balance and ownerName
    • Return an object with fields for withdrawal(withdrawalAmount), deposit(depositAmount), getBalance(), and getOwnerName()
    • Add validation to ensure only appropriate withdrawals and deposits are allowed
  3. Test your solution in a browser.

Solution:

AdvancedFunctions/Solutions/closures.html
<!DOCTYPE html>
<html>
<head>
	<meta charset="utf-8">
	<title>Closures</title>
	<script>
		function bankAccount(ownerName) {
			var balance = 0;
			var ownerName = ownerName;
			return {
				withdrawal: function(withdrawalAmount) {
					if (withdrawalAmount > 0 && withdrawalAmount <= balance) {
						balance -= withdrawalAmount;
					}
				},
				deposit: function(depositAmount) {
					if (depositAmount > 0) {
						balance += depositAmount;
					}
				},
				getBalance: function() {
					return balance;
				},
				getOwnerName: function() {
					return ownerName;
				}
			}
		}
	</script>
</head>
<body>
	<h1>Closures</h1>
	<script>
		var myAccount = bankAccount('Jane Doe');
		myAccount.deposit(100);
		document.write('Current balance: $' + myAccount.getBalance());
		myAccount.withdrawal(75);
		document.write('<br>Current balance: $' + myAccount.getBalance());
		myAccount.withdrawal(2000); // this shouldn't work, since 2000 > current balance
		document.write('<br>Current balance: $' + myAccount.getBalance());
		myAccount.deposit(-2); // this shouldn't work, since -2 <= 0
		document.write('<br>Current balance: $' + myAccount.getBalance());
		document.write('<br>Account owner: ' + myAccount.getOwnerName());
	</script>
</body>
</html>

Code Explanation

In function bankAccount we set local variables balance to 0 and ownerName to the string argument supplied when the function is first called.

Function bankAccount returns an object where each field is a function and thus a closure: this ensures that external code can get (myAccount.getBalance(), myAccount.getOwnerName()) and set (myAccount.deposit(100), myAccount.withdrawal(75)) properties, but external code cannot directly access nor modify properties.

Immediately Invoked Function Expressions (IIFEs)

Earlier in this lesson we looked at function expressions, creating a function like this:

var Foo = function(bar) {
	return bar + 3;
}

We might then call the function like this:

document.write(foo(4));

which would write 7 to the screen.

Because JavaScript treats any code wrapped in parentheses as an expression, another way to write a function expression, and to invoke it immediately, is like this, as an Immediately-Invoked Function Expression:

(function(bar) {
	return bar + 3;
})(4);

Our function - an anonymous function, in this case, since it has no name - is wrapped in parentheses and is thus treated by JavaScript as a function expression and not a function declaration. The (4) immediately following is an invocation of the function: we execute the function (that's the "Immediately-Invoked" bit) and pass in the value 4 for the parameter bar.

A Immediately-Invoked Function Expression (IIFE, often pronounced "iffy") without any parameters would look like this:

(function() {
	// body of function here
})();

where, as above, the () at bottom is an invocation of the function.

We can use IFFEs to create closures, since the function expressions are invoked immediately and properties inside of them are scoped to the expression.

We'll look next at two examples where we add click handlers to a page. In the first example (without an IIFE closure) the code doesn't work as intended; in the second example we fix the problem using an IIFE closure.

Code Sample:

AdvancedFunctions/Demos/divClick1.html
<!DOCTYPE html>
<html>
<head>
	<meta charset="utf-8">
	<title>Div Click 1</title>
	<style>
		div {
			width:100px;
			height:100px;
			float:left;
			margin-right:10px;
			border:1px solid #ff7800;
			background:#eee;
			text-align: center;
			font-size:28px;
			line-height: 100px;
		}
	</style>
	<script>
		window.onload = function() {
			var divs = document.getElementsByTagName('div');
			for (var i=0; i<divs.length; i++) {
				divs[i].addEventListener('click', function(e) {
					e.preventDefault();
					alert('you clicked div ' + i);
				}, 'false');
			}
		}
	</script>
</head>
<body>
	<h1>Div Click 1</h1>
	<div>0</div>
	<div>1</div>
	<div>2</div>
	<div>3</div>
	<div>4</div>
	<div>5</div>
</body>
</html>

Code Explanation

In divClick1.html, we add six divs to the page, styled to line up horizontally as squares and numbered 0 through 5.

On the event of window.load, we get all of the divs on the page, use a for loop to iterate over the collection of divs, and add a click handler which alerts the message 'you clicked div ' + i.

But, when we try out our page in a browser, it doesn't work as we had hoped: clicking any div results in an alert with the message you clicked div 6. The reason is that, by the time that any div is clicked, the value of parameter i is 6 (following the last iteration of the for loop).

We can fix this by using an IFFE to create a closure:

Code Sample:

AdvancedFunctions/Demos/divClick2.html
<!DOCTYPE html>
<html>
<head>
	<meta charset="utf-8">
	<title>Div Click 2</title>
	<style>
		div {
			width:100px;
			height:100px;
			float:left;
			margin-right:10px;
			border:1px solid #ff7800;
			background:#eee;
			text-align: center;
			font-size:28px;
			line-height: 100px;
		}
	</style>
	<script>
		window.onload = function() {
			var divs = document.getElementsByTagName('div');
			for (var i=0; i<divs.length; i++ ) {
				(function(i) {
					divs[i].addEventListener('click', function(e) {
						e.preventDefault();
						alert('you clicked div ' + i);
					}, 'false');
				})(i);
			}
		}
	</script>
</head>
<body>
	<h1>Div Click 2</h1>
	<div>0</div>
	<div>1</div>
	<div>2</div>
	<div>3</div>
	<div>4</div>
	<div>5</div>
</body>
</html>

Code Explanation

In divClick2.html, we again add six divs to the page and use a for loop to add a click handler to each one.

This time, however, we use an IFFE to create a closure when we create the click handler for each div. The function expression "remembers" the value of i at the time it is invoked, and thus clicks on any div correctly alert the message you clicked div 0, you clicked div 1, etc.

Callbacks

In JavaScript, callbacks are functions called by other functions which take the first function as a parameter. We can do this - pass a function to another function as an argument - because, in JavaScript, functions are objects. One of the key benefits of using callback functions is using them asynchonously: we want them to work, usually, in response to some event - but only when that event fires.

You are likely familiar with callback functions from event handling in JavaScript:

var myButton = document.getElementById("myButton");
myButton.addEventListener("click", someRandomFunction);

In the example above, we attach an event listener to the button with id myButton, listening for clicks on that button. When a click happens - every time a click happens - we invoke the someRandomFunction function. It's not that we invoke/call function someRandomFunction when the click happens, but rather that we line up function someRandomFunction to be called ("called back") upon the event of a click.

Another benefit to using callbacks is flexibility: in passing a function as a parameter to another function, we can slot in different functionality per our needs. Here's an example:

Code Sample:

AdvancedFunctions/Demos/callbacksOperations.html
<!DOCTYPE html>
<html>
<head>
	<meta charset="utf-8">
	<title>Callbacks - Operations</title>
	<style>
		input {
			padding:4px;
			width:57px;
		}
		input, button {
			padding:2px 5px;
			font-size:20px;
		}
	</style>
	<script>
		function doOperation(x, y, callbackFunction) {
			return callbackFunction(x, y);
		}
		function doAdd(x, y) {
			return x + y;
		}
		function doSubtract(x, y) {
			return x - y;
		}
		function doMultiply(x, y) {
			return x * y;
		}
		function doDivide(x, y) {
			return x / y;
		}

		function updateResult(e) {
			var targetID = e.target.id;
			var num1 = parseFloat(document.getElementById('num1').value);
			var num2 = parseFloat(document.getElementById('num2').value);
			var result = document.getElementById('result');
			switch (targetID) {
				case 'doAdd':
					var doOp = doAdd;
					break;
				case 'doSubtract':
					var doOp = doSubtract;
					break;
				case 'doMultiply':
					var doOp = doMultiply;
					break;
				case 'doDivide':
					var doOp = doDivide;
					break;
			}
			result.value = doOperation(num1, num2, doOp);
		}

		window.onload = function() {
			
			var buttons = document.getElementsByTagName('button');

			for (var i=0; i<buttons.length; i++ ) {
				buttons[i].addEventListener('click', function(e) {
					updateResult(e);
				}, 'false');
			}
		}
		
	</script>
</head>
<body>
	<h1>Callbacks - Operations</h1>
	<input type="text" id="num1">
	<input type="text" id="num2">
	<button id="doAdd" class="op">+</button>
	<button id="doSubtract" class="op">-</button>
	<button id="doMultiply" class="op">*</button>
	<button id="doDivide" class="op">/</button>
	<input type="text" id="result">
</body>
</html>

Code Explanation

The HTML markup for the page includes textfields for two numbers, four buttons (for operations "add", "subtract", "multiply", and "divide"), and a textfield for the result of performing the operation on the two user-entered numbers.

On the event of window.load, we attach an event listener to each button, calling function updateResult and passing to it the parameter e, the event object that contains details about the event that was triggered.

Function updateResult gets the value of the two numbers (converting them to integers) and, based on the id of the element that generated the event (doAdd, doSubtract, doMultiply, or doDivide, uses a switch statement to set a local variable, doOp as appropriate. We then set DOM element result's valuebased on function doOperation with the approprite callback function.

Note that we use parseFloat to convert the field values from a string to a floating-point number, so that we can use numeric values in our operations.

Function doOperation returns callbackFunction(x, y), where callbackFunction is the function passed in when doOperation is called.

Using callback functions in this manner gives us great flexibility:

  • Our "operation" functions (doAdd, doSubtract, etc.) can be tailored to just focus on the operations - a programming principle known as "Separation of Concerns".
  • We might do some validation inside doOperation to check to make sure we have the right values for our numbers ("divisor can't be zero" etc.).
  • A pattern like the one we have here would make it easy to import a library, say from a third-party developer, and easily add more-complex mathematical opertions easily to our existing page.

Recursion

Recursion in JavaScript is, like in any functional programming language, the process of a function calling itself. Many real-life phenomena lend themselves to recursion. Consider the process of generating factorial numbers: x! ("x factorial") is defined as x * (x-1) * (x-2) ... * 1. For example:

4! = 4 * 3 * 2 * 1 = 24

3! = 3 * 2 * 1 = 6

2! = 2 * 1 = 6

1! = 1 = 1

0! = 1

Note that, by definition, 0! = 1.

The astute observer will quickly recognize that it is always the case that

x! = x * (x-1)!

that is, we can find the factorial for any number by multiplying the number itself by the factorial of the number one less, until we reach 0 (and, thus, stop the process.)

The example above illustrates the two things we need to employ recursion: a way to make a larger problem a little bit smaller, and a way to know when to stop. Let's look at a code example to see how this works.

Code Sample:

AdvancedFunctions/Demos/recursionFactorial.html
<!DOCTYPE html>
<html>
<head>
	<meta charset="utf-8">
	<title>Recursion - Factorial</title>
	<style>
		input {
			padding:4px;
			width:57px;
		}
		input, button {
			padding:2px 5px;
			font-size:20px;
		}
	</style>
	<script>
		function factorial(x) {
			if (x == 0) {
				return 1;
			} else {		
				return (x * factorial(x-1));
			}
		}

		window.onload = function() {
			var result = document.getElementById('result');
			document.getElementById('doFactorial').addEventListener('click', function(e) {
				var num = parseInt(document.getElementById('num').value);
				result.value = factorial(num);
			}, 'false');
		}
		
	</script>
</head>
<body>
	<h1>Recursion - Factorial</h1>
	<input type="text" id="num">
	<button id="doFactorial">!</button>
	<input type="text" id="result">
</body>
</html>

Code Explanation

Our page listens for clicks on the #doFactorial button, getting the value of the left textfield as num and setting the value of the right textfield to factorial(num).

Function factorial is defined to use recursion: if the argument x passed to it is 0, then we return 1. If not (and we assume that only integers greater than 0 are passed to our function), then the function calls itself, passing x-1 as the parameter. Thus:

factorial(3) =

3 * factorial(2) =

3 * 2 * factorial(1) =

3 * 2 * 1 * factorial(0) =

3 * 2 * 1 * 1 =

6

Another example is the Fibonacci sequence, a list (sequence) of numbers defined as follows:

  • The first number is always 1.
  • The second number is always 1.
  • Each successive number is defined as the sum of the previous two numbers.

Thus the first six number in the Fibonacci sequence are:

1, 1, 2, 3, 5, 8

Following is an example in JavaScript of a recursive function to generate the first n numbers of the Fibonacci sequence:

Code Sample:

AdvancedFunctions/Demos/recursionFibonacci.html
<!DOCTYPE html>
<html>
<head>
	<meta charset="utf-8">
	<title>Recursion - Fibonacci</title>
	<style>
		input {
			padding:4px;
			width:57px;
		}
		input, button {
			padding:2px 5px;
			font-size:20px;
		}
	</style>
	<script>
		function fibonacci(n) {
			if (n == 1 || n == 2) {
				return 1;
			} else {
				return (fibonacci(n-1) + fibonacci(n-2));
			}
		}

		window.onload = function() {
			var result = document.getElementById('result');
			document.getElementById('doFibonacci').addEventListener('click', function(e) {
				var num = parseInt(document.getElementById('num').value);
				result.innerHTML = '';
				for(var i=1;i<=num;i++) {
					result.innerHTML += fibonacci(i);
					if (i < num) {
						result.innerHTML += ', ';
					}
				}
			}, 'false');
		}
		
	</script>
</head>
<body>
	<h1>Recursion - Fibonacci</h1>
	<input type="text" id="num">
	<button id="doFibonacci">Go</button>
	<div id="result"></div>
</body>
</html>

Code Explanation

Our page listens for clicks on the #doFibonacci button, getting the value of the left textfield as num and setting, via a for loop, the innerHTML of the #result div to the first num elements of the Fibonacci sequence.

Function Fibonacci returns the nth number of the Fibonacci sequence. If the parameter n is 1 or 2, then the function returns 1; if not - that is, if n is greater than 2 - then the function finds the value recursively, returning:

Fibonacci(n-1) + Fibonacci(n-2)

We'll ask you to try out using recursion in the next exercise:

Recursion

Duration: 20 to 30 minutes.

In this exercise, you will create a function that finds the maximum value among the elements of an integer array.

  1. Open AdvancedFunctions/Exercises/findMax.html for editing.
  2. Where indicated in the for loop inside the window.onload handler: generate a random number, add it to the array a, and write the number to the screen.
  3. Write the body of function FindMax which, when passed an array of integers, should return the greatest value in the array. Write the function using recursion, per the following strategy:
    • If the array parameter arr has one element, return that element as the max.
    • Otherwise, the max value is either the first element or the maximum of the remaining part of the array.
    • You can use arr.slice(1) to get the "all but the first element" portion of the array.
  4. Test your solution in a browser.

Solution:

AdvancedFunctions/Solutions/findMax.html
<!DOCTYPE html>
<html>
<head>
	<meta charset="utf-8">
	<title>Find Max</title>
	<style>
		#arrayDisplay {
			font-size:24px;
			margin-bottom:5px;
		}
		button {
			padding:2px 5px;
			font-size:20px;
		}
	</style>
	<script>
		function findMax(arr) {
			if (arr.length == 1) {
				return arr[0];
			} else {
				var max1 = arr[0];
				var max2 = findMax(arr.slice(1));
				if (max1 > max2) {
					return max1;
				}
				else  {
					return max2;
				}
			}
		}

		window.onload = function() {
			var a = [];
			var arrayDisplay = document.getElementById('arrayDisplay');
			arrayDisplay.innerHTML = '';
			for(var i=0; i<10; i++) {
				var randomNum = Math.floor((Math.random() * 200) + 1) - 50;
				a.push(randomNum);
				arrayDisplay.innerHTML += a[i];
				if (i < 9) {
					arrayDisplay.innerHTML += ', ';
				}
			}

			var resultDisplay = document.getElementById('resultDisplay');
			document.getElementById('doFindMax').addEventListener('click', function(e) {
				resultDisplay.innerHTML = '';
				resultDisplay.innerHTML = 'The max is: ' + findMax(a);
			}, 'false');
		}
		
	</script>
</head>
<body>
	<h1>Find Max</h1>
	<div id="arrayDisplay"></div>
	<button id="doFindMax">Find Max</button>
	<div id="resultDisplay"></div>
</body>
</html>

Code Explanation

We generate a random number with Math.floor((Math.random() * 200) + 1) - 50 (subtracting "50" to make some of the numbers negative), add the random number to the array with a.push(randomNum), and write the number to the screen with arrayDisplay.innerHTML += a[i].

Our recursive findMax function first checks the length of its array parameter arr, returning the first (and only) element if the length is 1.

If not - that is, if the array has length of at least 2 elements - then the function compares the first element (arr[0]) with the rest (findMax(arr.slice(1))) of the array, with the latter being a recursive call to findMax. The function returns the larger of the two as the maximum value.