Learn JavaScript in Construct, part 6: More on functions

18

Index

Features on these Courses

Stats

7,782 visits, 16,292 views

Tools

Translations

This tutorial hasn't been translated.

License

This tutorial is licensed under CC BY-NC 4.0. Please refer to the license text if you wish to reuse, share or remix the content contained within this tutorial.

Published on 22 Oct, 2021. Last updated 16 Dec, 2021

Recursion

Functions can also call themselves. This is called recursion. For a function to be able to call itself, it must have a name to refer to itself by.

Note that if a function always calls itself, it has a similar effect to an infinite loop: the process will never and and the program will hang or crash. Therefore it's important to make sure a recursive function does end at some point.

To illustrate recursion, let's write a function to calculate the factorial of a number. For example 5 factorial, also written 5!, is 5 x 4 x 3 x 2 x 1 = 120.

This could also be done with a loop. However we'll use a recursive function to demonstrate the principle of recursion.

function factorial(n)
{
	if (n === 1)
	{
		return 1;
	}
	else
	{
		// Recursion happens here
		return n * factorial(n - 1);
	}
}

console.log(`5! = ${factorial(5)}`);

This will log 5! = 120 to the console.

The key part that causes recursion is n * factorial(n - 1), which means the factorial function is calling itself again, but with a different parameter. This means when passed with 5, it will calculate 5 * factorial(4); calling factorial(4) will calculate 4 * factorial(3), and so on until n is 1.

Notice that there is an 'if' statement that specifically checks if (n === 1) and returns 1 (since 1! = 1). Note that in this case it does not call itself again. This is important to make sure the recursion ends! Otherwise it would carry on forever, reducing n down in to the negative numbers without ever stopping.

Here's the equivalent factorial function written with a 'for' loop. Notice in this case the 'for' loop uses the parameter as the loop variable (omitting declaring its own variable), and decrements it down until n is 1 (at which point n > 1 is false). This means the loop will repeat with n counting down, e.g. 5, 4, 3, 2, each time multiplying the product. It skips multiplying by 1, but that doesn't matter, as multiplying by 1 does not change the number.

function factorial(n)
{
	let product = 1;
	
	for ( ; n > 1; n--)
	{
		product *= n;
	}
	
	return product;
}

console.log(`5! = ${factorial(5)}`);

As noted this is also a perfectly reasonable way to implement the function, but we used this as a way to demonstrate the principle of recursion with functions. There are times when recursion is more convenient than loops, such as when processing certain data structures.

Arrow functions

JavaScript provides a shorthand syntax for functions. This is based on equals and greater-than characters: =>. In this context, it has nothing to do with comparisons: the two characters are meant to look like a little arrow, hence the name arrow functions. When you see this arrow, you know you're looking at a function. (Try not to mix it up with the less than or equal comparison operator <= - the arrow for arrow functions points right.)

Arrow functions cannot have a name, and so always work as a function expression. To demonstrate the syntax, here's a standard function expression for adding two numbers.

function (a, b)
{
	return a + b;
}

This can be written as an arrow function like so:

(a, b) =>
{
	return a + b;
}

Notice the function keyword is not used: instead the "arrow" => comes after the parameters.

The arrow syntax can be reduced further. If there is only a single return statement inside the function body, the braces and the return keyword can be omitted. Note these cannot be omitted with the standard function syntax.

(a, b) => a + b

Notice how much shorter this is than what we started with - but all three examples above work identically. These are just different ways to write the same thing.

There are two more things to note about arrow functions. Firstly if there is only one parameter, the parenthesis around the parameters are optional. For example an arrow function to add 1 to a number could be written either of the two ways below.

(a) => a + 1
a => a + 1

// Equivalent to:
function (a)
{
	return a + 1;
}

If the function has no parameters, it can use an empty parameter list with ().

() => "Hello world!"

// Equivalent to:
function ()
{
	return "Hello world!";
}

One common technique you may see is to instead use a single unused parameter instead of (). Often the unused parameter is named just _ for brevity, as a single underscore is a valid parameter name in JavaScript. For example both the following arrow functions don't use any parameters, but declare a single unused parameter just for shorthand.

unusedParam => "Hello world!"
_ => "Hello world!"

So if you see _ => in anyone else's code, remember it's not some special syntax, it's just the same as saying unusedParam => while trying to keep the code as short as possible.

To illustrate why the arrow function syntax is useful, let's revisit the logReturnValueOf example from before. It originally looked like this.

// Declare a function that calls the function passed as its parameter
function logReturnValueOf(func)
{
	console.log(`The function provided returned: ${func()}`);
}

// Call the above function, and also give it a function to call
logReturnValueOf(function ()
{
	return "Hello world!";
});

The function passed in logReturnValueOf(...) takes no parameters, and just returns a value. So it can be rewritten like this.

// Declare a function that calls the function passed as its parameter
function logReturnValueOf(func)
{
	console.log(`The function provided returned: ${func()}`);
}

// Call the above function, and also give it a function to call
logReturnValueOf(() => "Hello world!");

This makes the call to logReturnValueOf much shorter and clearer.

Arrow functions have a number of other features, in particular handling the this keyword differently. However we're not going to cover these yet. For now, just be aware that if you see =>, it's just another way to write a function. This guide will occasionally use arrow functions where writing a function in a shorter way makes the code clearer.

  • 2 Comments

  • Order by
Want to leave a comment? Login or Register an account!
  • Now, knowing about that 'closure' thing I suspect: thats how actions in event sheets refers to each other inside one event. It still a mystery how long collected 'garbage' info is available down the events/sub events but I'm too afraid to dig deeper.

  • great!