Course: JavaScript

Progress (0%)

  1. Foundation

  2. Numbers

  3. Strings

  4. Conditions

  5. Loops

  6. Arrays

  7. Functions

  8. Objects

  9. Exceptions

  10. HTML DOM

  11. CSSOM

  12. Events

  13. Drag and Drop

  14. opt Touch Events

  15. Misc

  16. Project: Analog Clock

JavaScript Functions

Chapter 10 19 mins

Learning outcomes:

  1. What are functions
  2. Syntax of creating functions
  3. How to call functions
  4. What are parameters and arguments
  5. The return keyword

Introduction

One of the most rewarding concepts in programming is that of functions. Back in the day when programming was still in its early stages, there was absolutely nothing such as functions.

Luckily, however, people were already familiar with the idea of functions from mathematics. And that went quite well with being taken to programming. (Think about mathematical functions implemented in computer languages.)

In the end, as programming matured, functions became an integral part of computing. Today, we can hardly imagine any complex program without even the least amount of employment of functions.

In this chapter, we'll understand what exactly is meant by a function in JavaScript, followed by how to actually create one ourself. Then, we'll consider some predefined functions in JavaScript and see how they help us to perform some common tasks quickly.

Moreover, we'll also consider the notion of arguments and parameters (pretty much similar to the ones in mathematics) and then finally see how to use the return keyword to help resolve function calls with given values.

What are functions?

At the very core:

A function, in JavaScript, represents a block of code that can be executed at any time when the function is called.

To understand this definition, let's imagine a simple problem.

Suppose we want to add the variables a and b together and then log their sum.

Alright, very easy to do:

var a = 10;
var b = 20;
console.log(a + b);
30

And done.

Now suppose that we want to repeat this for 5 different pairs of numbers. Hmm.

Well, we can do all this manually as well, as shown below:

var a = 10;
var b = 20;
console.log(a + b);

a = 1000;
b = 200;
console.log(a + b);

a = -6;
b = 7;
console.log(a + b);

a = 1;
b = 101;
console.log(a + b);

a = 2;
b = 3;
console.log(a + b);

Clearly the code has become long-winded, but at least our job is done.

30 1200 1 102 5

Now suppose that we have 1000 such pairs of numbers. Moreover, this time instead of logging the sum of a and b, we want to log the sum of the sine of a and the cosine of b, where a and b are both in degrees.

Now what?

Well, it's clearly not impossible if done manually, but absolutely not elegant, nor flexible.

We can do much better.

This is what functions were created for — to group a piece of code that can be executed whenever the need be. But as stated before, functions don't just group code and give us back a cryptic value to access. Nope.

Functions can also be named just like we could name variables. What this means is that we can not only just group code using functions, but also use the function's name to describe the purpose of the code. As you may have guessed, this can drastically improve the readability of code.

For instance, if we were to group the code in the example above inside a function, we could name it processVariables, following from the fact that the code simply processes the variables a and b, and then call this function whenever required to.

Let's now see how to create a function in JavaScript and then execute the code inside it by means of calling the function.

Creating a function

A function in JavaScript is created using the function keyword.

Here's the syntax of defining the simplest function:

function functionName() {
   ...
}

First comes the function keyword, followed by the name of the function (which must obey all variable naming rules of JavaScript), followed by a pair of parentheses (()), followed by a pair of curly braces ({}).

The code inside the pair of curly braces ({}) is known as the function's body. Altogether, this is called the definition of the function.

First of all, note that the curly braces ({}), surrounding a function's body, are part of the syntax of defining a function. They don't denote a block statement and aren't optional.

That is, we can't have the following:

function functionName() statement;
Uncaught SyntaxError: Unexpected identifier

The proper way to express the code above is as follows:

function functionName() {
   statement;
}

Small details do matter sometimes.

Once a function is created, its code is alloted the desired space in memory. Yes, that's right; even code itself could be stored in memory. And then, it sits there idle until the function is called.

So what is meant by 'calling' a function?

Recall that we said earlier that a function represents a block of code that can be executed at any time when the need be. That execution 'at any time' is done when we call the function.

Calling, or invoking, a function means to execute its body.

As with creating a function, there is a special syntax to invoke a function in order to distinguish it from merely referring to a variable in code.

That is, to succeed the function's name with a pair of parentheses (()), as follows:

functionName()

So for instance, to call the function processVariables, we'd use the expression processVariables().

The invocation of a function is an expression. Hence, we can use it just like we can use any other expression in JavaScript.

Now that we know how to create and call a function, let's consider a simple and quick example.

A simple example

Suppose we want to obtain input from the user and then alert the value input as follows: 'Input: <input>' where <input> is the value input.

Clearly, this ain't a difficult task — just call prompt() followed by calling alert(), and you're done.

The code below accomplishes this:

var input = prompt('Enter something:');
alert('Input: ' + input);

It works, but we want don't the code written directly in the script. Instead, we want it inside a function.

This is accomplished below:

function promptAndAlert() {
   var input = prompt('Enter something:');
   alert('Input: ' + input);
}

We call the function promptAndAlert following from its very underlying purpose — to first prompt the user to input something and then alert it. The body of the function is the exact same as the code we saw above.

Now, let's call this function in order to put its body into action:

function promptAndAlert() {
   var input = prompt('Enter something:');
   alert('Input: ' + input);
}

promptAndAlert();

Live Example

Great.

If you notice it, when nothing is input into the prompt and the OK button is pressed, the alert text is 'Input'. Now, we feel like changing this so that when the input is empty, the user should be prompted to input again after showing another alert asking him/her to not leave the input empty.

Let's do this.

Whether the given input is empty will be checked using a while loop, which will keep repeating the prompt() as long as the input remains empty. Right after the loop, we'll make the desired 'Input: <input>' alert.

Here's the code:

function promptAndAlert() {
   var input = prompt('Enter something:');

   while (input === '') {
      alert('The field can not be left empty');
      input = prompt('Enter something:');
   }
   alert('Input: ' + input);
}

promptAndAlert();

Live Example

Just as we are evolving this extremely basic function, we can appreciate the power of using functions. promptAndAlert() won't just ask the user for his/her input and then alert whatever that turns out to be. No. It instead checks that the input is not empty, and only the echoes back the provided input.

If we want to, we could call promptAndAlert() multiple times, and each time we'll be getting this very code executed, making sure that the given input is valid and then alerting it back.

Functions prove to be an exceptionally compelling idea in programming. And as soon as we incorporate the concept of parameters/arguments into them, and then the concept of return values, their power just skyrockets.

Let's see what exactly are function parameters and arguments.

Parameters and arguments

The pair of parentheses (()) in a function's definition and in its invocation expression is there for one very simple purpose — to hold the parameters and arguments of the function, respectively.

More often than not, functions require some additional data in order to perform their desired computation.

For instance, a function sum() might want to add two given numbers together. These numbers are provided to it as additional data. This additional data is often termed as arguments to the function.

An argument is a datum provided to a function so that it can use it to carry out its desired job.

The arguments of a function are provided inside the pair of parentheses (()) in its invocation expression. Multiple arguments are separated using commas (,).

So for example, in the expression sum(10, 20), 10 and 20 are the arguments passed on into sum().

A parameter is a related but slightly different idea.

When an argument is provided to a function, it obviously has to be held on somewhere inside the function. That 'somewhere' is called a parameter.

A parameter is a variable, local to a function, that holds the corresponding argument provided to the function.

Parameters are defined in the definition of a function, once again inside the pair of parentheses (()) after the function's name.

Since parameters are semantically just variables, they must abide by the variable naming rules of JavaScript. Furthermore, multiple parameters, as with multiple arguments, are separated by commas (,).

But how does the engine determine which argument to assign to which parameter?

Well this is extremely simple. The first argument goes with the first parameter, the second argument goes with the second parameter, and so on and so forth.

Let's now consider an example.

Below we define a function logSum() that's meant to take in two numbers a and b and then log their sum:

function logSum(a, b) {
   console.log(a + b);
}

Here, a and b are the parameters of logSum(). And once again, see how we've named the function — it immediately tells us that the function doesn't just compute the sum of the numbers, but also logs it.

Let's now call logSum() with a couple of numbers:

function logSum(a, b) {
   console.log(a + b);
}

logSum(10, 20);
logSum(-2, 3);
30 1

Here, the arguments to logSum() in the first call are 10 and 20, whereas in the second call they are -2 and 3.

Piece of cake.

If we provide more arguments than there are parameters of a given function, JavaScript has no issues — it won't throw an error:

function logSum(a, b) {
   console.log(a + b);
}

// More arguments than parameters.
logSum(10, 20, 30);
30

It'll just use the arguments that it needs to and ignore the rest of them.

Similarly, if the number of arguments is less than the number of parameters, even then JavaScript won't throw an error. Each of the parameters that aren't provided an argument to gets assigned the value undefined (just like a declared but non-initialized variable).

Here's an example:

function logSum(a, b) {
   console.log(a + b);
}

// Less arguments than parameters.
logSum(10);
NaN

logSum(10) calls logSum() with a = 10 and b = undefined since no argument is provided for the second parameter b.

As we'll cover in JavaScript Numbers unit, adding a number to undefined yields the special number NaN which, when logged, gets displayed literally as 'NaN'.

Now depending on the situation, this lenient behavior of JavaScript can be either desirable or irritating.

In the case of providing more arguments than there are parameters, we can safely ignore that as it couldn't really cause any problem in any situation, whatsoever. After all, the parameters on which the function operates do have their corresponding values.

But in the case of providing less arguments than there are parameters, we do need a solution.

If a given parameter's value is undefined, that can be a really good signal that the corresponding argument wasn't provided. However, if this ain't the case, then we can proceed with the fact that at least some value is provided to us; whether that's valid or not for the function is a separate discussion.

In the code below, we modify logSum() slightly to ensure that it's called with at least two arguments; if that's not the case, an error message is logged:

function logSum(a, b) {
   if (a === undefined || b === undefined) {
      console.log('logSum() requires at least two arguments.');
   }
   else {
      console.log(a + b);
   }
}

logSum();
logSum(10);
logSum(10, 20);
logSum() requires at least two arguments. logSum() requires at least two arguments. 30

Note that when a parameter is equal to undefined, this doesn't always mean that no argument was provided. For instance, we can call a function explicitly providing the argument undefined.

In the code below, we call logSum() with two arguments, yet it fails to recognize them:

logSum(undefined, undefined)
logSum() requires at least two arguments.

But clearly, there is no point of such an invocation (who would want to provide undefined explicitly to a function?), and likewise we can safely rely on the method above to check whether a parameter was given a corresponding argument or not.

The return keyword

Once we're done with understanding the essence of parameters/arguments in a function, the next step is to consider another significant aspect of functions in nearly all languages — returning values.

In the mathematical arena, functions typically take in a couple of arguments and then return back a given value. For instance, the function ::f:: defined as ::f(x) = 2x:: would return ::20:: when provided the value ::10:: (as in ::f(10)::).

This idea applies to functions in programming as well. That is, when we call a function, whatever value it returns is used in place of the respective invocation expression. Therefore, if the function sum(), taking in two arguments, returns back their sum, then sum(10, 20) would evaluate down to 30.

But how do we return a given value from a function?

Simple — using the return keyword.

Here's the syntax of return:

function functionName(param1, param2, ..., paramN) {
   // ...
   return expression;
}

Once the engine encounters the return keyword, it computes the following expression expression and then immediately exits the function with the value of the expression. Any code after the return statement is ignored.

Let's consider an example.

Below we define a function sum() that takes in two arguments and returns back their sum:

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

Notice how we've named the function this time as sum() contrary to the function logSum(). Since the function doesn't log any sum here, there is no need to call it 'logSum' — just simply 'sum'. Another good name could be add().

Anyways, let's invoke this function with a couple of pairs of numbers:

sum(10, 20)
30
sum(0, -1)
-1
sum(3, 200)
203
sum(-10.8, -3.2)
-14

Thanks to the return keyword, the function computes the sum of the given numbers and then returns the result.

Now we could use sum() just like any other number in any expression. Here are some examples:

sum(sum(10, 20), 30)
60
var x = sum(1, 5);
undefined
x
6
sum(3, 200) - 10
193
2 ** sum(10, 1)
2048

Great!

Now, let's come back to the exit-behavior of return.

Consider the following:

function test() {
   console.log('Hello');
   return;
   console.log('World!');
}

test();

What do you think will test() log?

Well, it'll only log 'Hello', not 'World!'.

Hello

That's simply because the second log in the code above succeeds the return statement, and the moment return is encountered, all the code after it gets ignored.

In almost all cases, as we shall see throughout this course, this behavior of exiting exhibited by return is desirable. We can use it to check for edge cases inside a function and, thus, end execution when there is no point of continuing forward.

Undoubtedly, return is one of the most useful and powerful keywords in all programming languages. As you'll create more and more JavaScript programs, you'll appreciate this proposition more and more.