How to Create Functions in JavaScript

In a real-world project, you might have pieces of code for different purposes. For instance, you could have a for loop that processes the elements in an array, another piece of code that asks the user to provide an input, and many more.

If not organized appropriately, this would put a lot of pressure on future maintenance. Not only because it is very easy to lose track, but also because there is no way to reuse your code, you'll have to rewrite it over and over again.

Luckily, there is a fix. Function is a way for you to organize pieces of your program.

How to define functions

JavaScript offers three different ways to define a function: function expression, function declaration, and arrow function. Let's start with the function expression syntax.

Function expression

For instance, here is an example of a function that counts all even numbers in the array:

javascript
1let countEven = function (arr) {
2  let n = 0;
3  let e;
4
5  for (e of arr) {
6    if (e % 2 === 0) {
7      n++;
8    }
9  }
10
11  return n;
12};

The keyword function defines a function in JavaScript, and the parentheses define the function's input arguments. In this case, the function only accepts one input argument, arr, which can then be used inside the function as a variable.

Look inside the function body, defined by the curly braces ({}), and notice that the input argument arr is treated as an array, and we are iterating over the array with the for of loop.

At the end of the function body, right before the closing }, the final result (n) will be returned using the keyword return, which also marks the end of the function. The function will terminate after the return statement, so any statements afterward will be ignored.

If you don't have a return statement in the function, that function will return undefined instead.

Lastly, the function will be assigned to the variable countEven, and to invoke that function, simply call by its name and pass the required input arguments.

javascript
1let arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
2
3console.log(countEven(arr));

The built-in function console.log(), which we've seen many times in this course, will take the output of countEven(), and print it to the console.

text
15
You can simplify this function a little bit by declaring the e element inside the for loop like this:
javascript
1let countEven = function (arr) {
2  let n = 0;
3
4  for (let e of arr) {
5    if (e % 2 === 0) {
6      n++;
7    }
8  }
9
10  return n;
11};

This syntax is called function expression. Some people find it difficult to write, compared to the function declaration syntax which we are going to discuss later, but it does demonstrate what a function is.

A function is just a piece of code as a value, which is then assigned to a variable.

Function declaration

There is also a slightly shorter way of creating a function called function declaration, which is demonstrated below:

javascript
1function countEven(arr) {
2  let n = 0;
3
4  for (let e of arr) {
5    if (e % 2 === 0) {
6      n++;
7    }
8  }
9
10  return n;
11}

Here we are using the same function keyword, countEven is the function name, and everything else remains the same.

This function can be called in the exact same way:

javascript
1let arr = [1, 2, 3];
2
3countEven(arr);

Arrow function

Alternatively, there is a special syntax called arrow function in JavaScript, which aims to provide an even shorter way to create functions.

javascript
1let countEven = (arr) => {
2  let n = 0;
3
4  for (let i = 0; i < arr.length; i++) {
5    if (arr[i] % 2 === 0) {
6      n++;
7    }
8  }
9
10  return n;
11};
12
13let a = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
14
15console.log(countEven(a));

The name arrow function comes from the arrow (=>).

The arrow function can be expressed in a compact format under certain scenarios. For example, the parentheses can be omitted when the function only takes one input parameter.

javascript
1let countEven = arr => {
2  . . .
3};

When the function body has only one statement, the curly braces and even the keyword return can be omitted.

javascript
1// prettier-ignore
2let calcSquare = x => x * x;
3
4console.log(calcSquare(5));
text
125

The differences

These three methods do have some slight differences. First of all, by default, JavaScript executes the code line by line. When using the function expression syntax, you can only call a function after it has been declared.

javascript
1let arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
2
3console.log(countEven(arr)); // <--
4
5let countEven = function (arr) {
6  let n = 0;
7
8  for (let e of arr) {
9    if (e % 2 === 0) {
10      n++;
11    }
12  }
13
14  return n;
15};

In this example, the function countEven() is called before it is declared. And this code will return an error.

text
1/Users/. . ./index.js:3
2console.log(countEven(arr)); // <--
3            ^
4
5ReferenceError: Cannot access 'countEven' before initialization
6    at Object.<anonymous> (/Users/. . ./index.js:3:13)
7    . . .
8
9Node.js v20.12.2

The arrow function works the same. An error will be returned if you try to call an arrow function before it is declared.

javascript
1let arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
2
3console.log(countEven(arr)); // <--
4
5let countEven = (arr) => {
6  let n = 0;
7
8  for (let e of arr) {
9    if (e % 2 === 0) {
10      n++;
11    }
12  }
13
14  return n;
15};
text
1/Users/. . ./index.js:3
2console.log(countEven(arr)); // <-- The function countEven() is called before it is declared.
3            ^
4
5ReferenceError: Cannot access 'countEven' before initialization
6    at Object.<anonymous> (/Users/. . ./index.js:3:13)
7    . . .
8
9Node.js v20.12.2

However, the function declaration method is different. JavaScript will compile all the declared functions first, and then start to execute the code from the first line, which means you can call a function before it is declared.

javascript
1let arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
2
3console.log(countEven(arr)); // <--
4
5function countEven(arr) {
6  let n = 0;
7
8  for (let e of arr) {
9    if (e % 2 === 0) {
10      n++;
11    }
12  }
13
14  return n;
15}
text
15

This provides you with a more flexible way to organize your functions. For example, you can place all of your functions together at the beginning or the end of the file, without worrying about any conflicts.

Another difference has to do with the this keyword, which refers to the current instance of the object. Arrow functions don't have a this keyword like regular functions. We will come back to this topic after we've discussed more about objects.

Function arguments

The functions in our previous examples only accept one input argument, but in fact, JavaScript functions are pretty flexible about the number of arguments you give them. It is possible to define a function that accepts a list of arguments, optional arguments, or even an indefinite number of arguments.

When the function must deal with multiple input arguments, you can separate them with commas. For example, sum3() is a function that calculates the sum of three numbers.

javascript
1let sum3 = function (num1, num2, num3) {
2  return num1 + num2 + num3;
3};

The function declaration syntax and the arrow function work similarly.

javascript
1function sum3(num1, num2, num3) {
2  return num1 + num2 + num3;
3}
javascript
1let sum3 = (num1, num2, num3) => num1 + num2 + num3;

This function requires three arguments, and when when you call the function with less than three arguments, the ones left out will be assigned undefined.

javascript
1function sum3(num1, num2, num3) {
2  console.log(`num1 is ${num1}`);
3  console.log(`num2 is ${num2}`);
4  console.log(`num3 is ${num3}`);
5  return num1 + num2 + num3;
6}
7
8console.log(sum3(1, 2));
javascript
1num1 is 1
2num2 is 2
3num3 is undefined
4NaN

If you pass too many arguments, the extra ones will simply be ignored.

This flexibility can be useful in practice, as it enables you to create functions that accept any number of arguments, but it does lead to problems sometimes.

For instance, in our previous example, JavaScript cannot calculate 1 + 2 + undefined, so it returns NaN, not a number.

To prevent this from happening, it is best to give the argument a default value.

javascript
1function sum3(num1, num2, num3 = 0) {
2  console.log(`num1 is ${num1}`);
3  console.log(`num2 is ${num2}`);
4  console.log(`num3 is ${num3}`);
5  return num1 + num2 + num3;
6}
javascript
1console.log(sum3(1, 2));

This way, instead of undefined, num3 will be assigned 0 if a value is not provided when the function is called.

Functions as values

At the beginning of this lesson, we defined a function as a piece of code as a value, which is assigned to a variable.

This definition is in fact, a very important concept in JavaScript, and we have to talk more about it. Understanding this concept allows you to write code at a higher level.

  • Return a function

We know from the past examples that the return statement can return a variable, so naturally, it can return a function as well.

javascript
1function a() {
2  console.log("Function a executed");
3
4  return function b() {
5    console.log("Function b executed");
6  };
7}

You can call the function a() like this:

javascript
1a();
text
1Function a executed

Executing function a() will return a function, and you can assign this returned function to a variable.

javascript
1let x = a();

x will become a variable with a function attached to it, and you can execute the function like this:

javascript
1let x = a();
2
3x();
text
1Function a executed
2Function b executed
  • Accept a function as an input argument

A function can accept variables as the input argument, so naturally, it can accept functions as well.

javascript
1function decide(status, yes, no) {
2  if (status) {
3    yes(); // If status is true, execute this function
4  } else {
5    no(); // If status is false, execute this function
6  }
7}

In this case, arguments yes and no are expected to be functions. If status is true, function yes() will be executed. If status is false, function no() will be executed.

Next, let's create functions a() and b().

javascript
1function a() {
2  console.log("Function a executed");
3}
4
5function b() {
6  console.log("Function b executed");
7}
8
9decide(true, a, b);
10decide(false, a, b);
text
1Function a executed
2Function b executed

In this case, function a() is passed to decide() as the argument yes, and function b() is passed as the argument no.

  • Functions defined inside functions

You can define variables inside a function, so naturally, you can define functions as well.

javascript
1function out(status) {
2  function a() {
3    console.log("Function a executed");
4  }
5
6  function b() {
7    console.log("Function b executed");
8  }
9
10  if (status) {
11    a();
12  } else {
13    b();
14  }
15}

Inside the function out(), there are two other functions, a() and b(). The out() function takes one input argument, status. If status is true, function a() will be executed, and if status is false, function b() will be executed.

javascript
1out(true);
2out(false);
text
1Function a executed
2Function b executed
  • Copy the function to another variable

You can copy a value to another variable like this:

javascript
1let a = 10;
2
3let b = a;
4let x = b;
5
6console.log(a);
7console.log(b);
8console.log(x);
text
110
210
310

So, a function can also be copied to another variable, and you can call that function with the new name.

javascript
1function a() {
2  console.log("Function executed");
3}
4
5let b = a;
6let x = b;
7
8a();
9b();
10x();
text
1Function executed
2Function executed
3Function executed

These functions that work on other functions are called higher-order functions. They are very useful in practice, and we will talk about them in detail.

At first, they can be difficult to understand, so to prepare yourself for the challenges that lie ahead, please take some time to truly understand this definition:

A function is just a piece of code as a value, which is assigned to a variable.

Lastly, a function can be placed inside an object as a property. In this case, the function will be called a method.

javascript
1let obj = {
2  name: "John Doe",
3
4  myFunction: function () {
5    console.log("Function executed");
6  },
7};
8
9obj.myFunction();
text
1Function executed

Why functions?

Take a look at this example:

javascript
1// Calculate the area of rectangle #1
2let length1 = 10;
3let width1 = 8;
4
5area1 = length1 * width1;
6
7// Calculate the area of rectangle #2
8let length2 = 15;
9let width2 = 3;
10
11area2 = length2 * width2;
12
13// Compare the area of two rectangles
14if (area1 < area2) {
15  console.log("Rectangle #1 is smaller than rectangle #2");
16} else if (area1 == area2) {
17  console.log("Rectangle #1 and rectangle #2 have equal area");
18} else {
19  console.log("Rectangle #1 is bigger than rectangle #2");
20}

This example calculates the area of two rectangles and then compare them, but notice that the first part (from line 1 to line 5) and the second part (from line 7 to line 11) are very similar. If we have more rectangles to compare, we'll just be repeating the same code over and over again.

In practice, you should always try to avoid that, because having more code means more space for potential mistakes, and makes your code difficult to read and understand. This would be an excellent chance to turn that code block into a function.

javascript
1function area(length, width) {
2  return length * width;
3}
4
5area1 = area(10, 8);
6area2 = area(15, 3);
7
8// Compare the area of two rectangles
9if (area1 < area2) {
10  console.log("Rectangle #1 is smaller than rectangle #2");
11} else if (area1 == area2) {
12  console.log("Rectangle #1 and rectangle #2 have equal area");
13} else {
14  console.log("Rectangle #1 is bigger than rectangle #2");
15}

And now your code is shorter and much easier to read.

Another thing we need to mention is the function name. When declaring a function, you should pick a name that is short but also descriptive. Here are some examples:

javascript
1function a() {. . .}
2
3function f() {. . .}
4
5function abc() {. . .}

These functions are short, but they don't adequately describe their purpose. For a real-life project, you will likely have to create dozens or even hundreds of functions. It is impossible to keep track of them if they are all named like f() or abc().

On the other hand, the following examples are descriptive, but are too long to be practical.

javascript
1function calculateTheAreaOfASquare() {. . .}
2
3function decideWhichChoiceIsBetter() {. . .}

In the best-case scenario, your functions should fit inside the program naturally like this:

javascript
1function isEven(number) {
2  return number % 2 === 0;
3}
4
5let num1 = 8;
6
7if (isEven(num1)) {
8  console.log(num1 + " is even");
9} else {
10  console.log(num1 + " is odd");
11}

In the field of programming, this is usually referred to as abstraction. As you know, the test for parity is one of the more cryptic expressions we have seen so far in this course. It is not immediately clear what the expression is supposed to do.

But in this case, we are hiding the expression behind the word isEven, allowing us to write the program at a higher and more abstract level.

This is also the second sign telling you that you need a function. When you are writing a program, and you encounter a feature that cannot be easily coded, and it feels like it requires a function.

For example, you might be building a feature that needs the user to be verified, and you need to test the user's status before taking the next step. In this case, it might be a good idea to put this feature behind a function.

javascript
1function userVerified(user) {
2  . . .
3}
4
5if (userVerified(user)) {
6  . . .
7} else {
8  . . .
9}

Now, whenever you need to verify a user, simply call the function userVerified(), which makes your code much easier to read.