Javascript 101: A Beginner's Guide to Functions

We're back for another round of Javascript 101. This series is aimed at those who are still new to the language. Together, we will explore fundamental topics of Javascript. If this is the first time you stumble upon a post of this series, make sure to have a look at these posts as well:

Today, we will be looking at functions. Functions can be described as reusable code patterns. Using them in your programs will reduce they amount of code you have to write. At the same time, they will give your program a natual structure, making it easier for others (and yourself) to understand your code.

Anatomy of a Function

There are two ways to declare a function in Javascript. Let's take a look at both patterns first:

Pattern A, function expression

var myFunction = function() {  
  console.log("hello");
}

Pattern B, function declaration

function myFunction() {  
  console.log("hello");
}

Both variants do exactly the same thing, they save the content of your function console.log("hello") to a variable called myFunction. You can choose the style you prefer. Now we have seen a function but we still don't know how it actually works. If you fire up a javascript console such as repl.it and enter our function, the result is quite disappointing. There is no "hello" appearing in the console. I can assure you that we didn't make a mistake in our function. The problem is that functions need to be called in your code. Javascript runs from the top to the bottom. If we have a code that looks like this:

console.log(1);  
console.log(2);  
console.log(3);  
console.log(4);  

We can be sure that the logs will appear in the right order. Now if we had a function that would take care of the third console log, could call it like this:

console.log(1);  
MyFunction();  
console.log(2);  
MyFunction();  
console.log(3);  
MyFunction();

function MyFunction() {  
  console.log('hello');
}

Our function is sitting comfortably at the bottom of our program, doing nothing. Javascript will ignore it entirely until we call it. Javascript then does the following: It logs the first console.log(1), then it notices that we want to call one of our functions. It sees the name of MyFunction and will then look for that function in your code and run all the code that is in that function. Upon completion, it will return to the space where it left off and continue with console.log(2). After that, it will once again go back into the function, execute all the code again and return. I think you get the idea. Ok, now we know that a function is a part of code that sits somewhere else in our program and waits patiently for us to call it. But wait, there is more.

Passing Values to Functions

You might have wondered what these brackets () behind our function are used for. In those brackets, we can pass values to our function. Why would we want to do this? Let's have a look an example function:

var myResult = sum(20,90);  
console.log(myResult); // logs 110  
myResult = sum(100,500);  
console.log(myResult); // logs 600

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

There are two new things happening with this function. First, we are passing two values to our function 20,90 in the first case and 100,500 in the second case. Within the function, we are using variables called a and b instead of the values. As those letters are variables, we can name them any way we want, they will always represent both numbers that have been passed to the function. A function can take none, only one or hundreds of values. You decide how many values your function will need to work. We are also using the keyword return here. By using the return statement, we can give a value back to our program. Think about it as a variable again. If you look at the line myResult = sum(100,500), instead of sum(100,500) Javascript will see the returned value 600. This is why we are able to assign this value to a variable. If our function would not return anything, myResult would be undefined. By the way, we don't even need to assign our sum(20,90) to a variable in order to work with it. We can use it just like any other value in our code:

console.log(sum(20,90)); // logs 110  
console.log(sum(100,500)); // logs 600  
console.log(sum(30,50) + sum(10,10)); // logs 100;

function sum(coolValue, anotherValue) {  
  return coolValue + anotherValue;
}

Note how I also changed the variable names in the function. It doesn't affect our code at all. However, as your functions grow more complex, it's advisable to use descriptive variable names. That will allow your colleagues to read your code without going insane.

Let's look at a few other examples of functions. As you might recall from the post on Array Methods, we can use a combination of string and array methods, to reverse a string. Here is a function we can use for this purpose:

console.log(reverseString("hello there"));  
console.log(reverseString("I am a cow"));

function reverseString(str) {  
  return str.split("").reverse().join("");
}

We have only looked at short functions in these examples but don't be fooled. Functions can grow quite large and contain many lines of code. We could have many lines of calculations and operations within our function before returning a final value;

myVar = doStuff(5);  
console.log(myVar); // logs 27.5

function doStuff(int) {  
  var myNumber = int;
  var halfNumber = myNumber / 2
  myNumber = halfNumber + myNumber * 3;
  myNumber += 10;
  return myNumber;
}

Functions and Scope in Javascript

A word that you will necessarily come across when reading about Javascript functions on the web is scope. The concept of scope describes which parts of your program can access certain variables and which ones can't. It's easiest to think of it like a waterfall in which the water is only flowing down. All your variables from your main program flow into your functions, so they have complete access to all variables that your main program created. If I change a variable of my main program in a function, it will stay changed. Even if the function doesn't return any value.

var myVar = 1;  
changeVar();  
console.log(myVar); //logs 5;

function changeVar() {  
  var myVar = 5;
}

Your main program, however, doesn't have access to the variables you create within a function (water doesn't flow up). The code below would return an error ReferenceError: anotherVar is not defined

var myVar = 1;  
createVar();  
console.log(anotherVar)

function createVar() {  
  console.log(myVar) // logs 5;
  var anotherVar = 10;
}

If we were to nest functions within each other, the water would continue to flow down. Functions nested within a parent function would have access to all variables of the main program scope as well as the parent function's variables. However, none of the parent functions would have access to the variables of their children.

Having this scope is a good thing. It helps with debugging functions since each function is a closed system. With each function having an own scope, we don't have to worry about reusing common variable names such as a,b,c,int,str in our functions. The scope also helps with memory usage. After the function has run, all variables that were used within a function will be removed from memory, freeing valuable resources.

When working with functions, your main program will hopefully become smaller and smaller and your code will be contained in separate, reusable elements.

In the next Javascript 101 post we will be looking at the HTML DOM. We will take everything we've learned from the previous lessons to finally modify HTML and create interactive website elements.

Further Reading:

Further down the rabbit hole