Lesson Overview

  • Define and invoke different kinds of functions.
  • Use the return value.
  • Explain function scope.

Functions

Functions are the main “building block” of our programs. They allow us to call code many times without repetition. That way we don’t have to write the same code over and over, it’s like storing a piece of code, that does a task inside a defined block.

function showMessage() {
    alert( 'Hello everyone!' );
  }

Everytime you make use of a JavaScript structure that features a pair of parentheses () and you’re not using a common built-in language structure like a for loop, while or do…while loop, or if…else statement, you are making use of a function.

function draw() {
  ctx.clearRect(0,0,WIDTH,HEIGHT);
  for (let i = 0; i < 100; i++) {
    ctx.beginPath();
    ctx.fillStyle = 'rgba(255,0,0,0.5)';
    ctx.arc(random(WIDTH), random(HEIGHT), random(50), 0, 2 * Math.PI);
    ctx.fill();
  }
}

This function draws 100 random circles inside a

<canvas>

element. Every time we want to do that, we can just invoke the function with this:

draw();

rather than having to write all the code again. Functions can contain whatever code you like – you can even call other functions from inside functions. The above example calls the random() function three times, which is defined by the following code:

function random(number) {
    return Math.floor(Math.random()*number);
  }

Function Parameters

Some functions require parameters to be specified when you are invoking them, these are values that need to be included inside the function parentheses, which it needs to do its job properly.

const myText = 'I am a string';
const newString = myText.replace('string', 'sausage');
// When you need to specify multiple parameters, they are separated by commas.

Sometimes parameters are optional and you don’t need to specify them. If you don’t, then the function will adopt some kind of default behavior.

const myArray = ['I', 'love', 'chocolate', 'frogs'];
const madeAString = myArray.join(' ');
console.log(madeAString);
// returns 'I love chocolate frogs'
const madeAnotherString = myArray.join();
console.log(madeAnotherString);
// returns 'I,love,chocolate,frogs'

Without a parameter to specify a joining/delimiting character, a comma is used by default.

Default parameters

If you’re writting a function and want to support optional parameters, you can specify default values by adding = after the name of the parameter, followed by the default value:

function hello(name = 'Chris') {
    console.log(`Hello ${name}!`);
  }

hello('Ari'); // Hello Ari!
hello();      // Hello Chris!

Anonymous functions

You can create functions that don’t have a name:

(function () {
    alert('hello');
  })

This is called an anonymous function. They are mostly used when a function expects to receive another function as a parameter. In this case the function parameter is often passed as an anonymous function.

Let’s say you want to run some code when the user types into a text box. To do this you can call the addEventListener() function of the text box. This function expects you to pass it (at least) two parameters:

  • the name of the event to listen for, which in this case is keydown
  • a function to run when the event happens.

When the user presses a key, the browser will call the function you provided, and will pass it a parameter containing information about this event, including the particular key that the user pressed:

function logKey(event) {
    console.log(`You pressed "${event.key}".`);
  }

textBox.addEventListener('keydown', logKey);

Instead of defining a separate logKey() function, you can pass an anonymous function into addEventListener():

textBox.addEventListener('keydown', function(event){
    console.log(`You pressed "${event.key}".`);
  });

Arrow Functions

If you pass an anonymous function like this, there’s an alternative form you can use, called an arrow function. Instead of “function(event)”, you write “(event) =>”:

textBox.addEventListener('keydown', (event) => {
    console.log(`You pressed "${event.key}".`);
  });

If the function only has one line in the curly brackets, you omit the curly brackets:

textBox.addEventListener('keydown', (event) => console.log(`You 
pressed "${event.key}".`));

If the function only takes one parameter, you can also omit the brackets around the parameter:

textBox.addEventListener('keydown', event => console.log(`You pressed 
"${event.key}".`));

If your function needs to return a value, and only contains one line, you can also omit the ‘return’ statement.

const originals = [1, 2, 3];
const doubled = originals.map((item) => item * 2);
console.log(doubled); // [2, 4, 6]

In the example above, (item) => item * 2 is the arrow function equivalent of:

function doubleItem(item) {
    return item * 2;
  }

Arrow functions are recommended, as they can make code shorter and more readable.

Scope

When you create a function, the variables and other things defined inside the function are inside their own separate scope, meaning that they are locked away in their own separate compartments, unreachable from code outside the functions.

The top level outside all your functions is called the global scope. Values defined in the global scope are accessible from everywhere in the code.

Return Values

Some functions don’t return a significant value, but others do. It’s important to understand what their values are, how to use them in your code, and how to make functions return useful values.

A return value is what the function returns when its completed.

const myText = 'The weather is cold';
const newString = myText.replace('cold', 'warm');
console.log(newString); // Should print "The weather is warm"
// the replace() string function takes a string,
// replaces one substring with another, and returns
// a new string with the replacement made

The ‘replace()’ function is invoked on the myText string, and is passed two parameters:

  1. the substring to find (‘cold’).
  2. the string to replace it with (‘warm’). When the function completes, it returns a value, which is a new string with the replacement made. In the code above, the result is stored in the variable newString.

Function parts

function favoriteAnimal(animal) {
    console.log(animal + " is my favorite animal!")
  }
favoriteAnimal('Goat')

In JavaScript, parameters are the items listed between the parentheses in the function declaration ((animal)). Function arguments are the values we pass to the function. The function definition is written on the first line: ‘function favoriteAnimal(animal)’. The parameter, ‘animal’, is just a placeholder for some future value. The last line, favoriteAnimal(‘Goat’), is where we call our function and we pass the value ‘Goat’ inside it, Goat is our argument in this case.

JavaScript Call Stack

JavaScript engine uses a call stack to manage execution contexts: the Global Execution Context and Function Execution Contexts. The call stack works based on the LIFO principle i.e., last-in-first-out. When you execute a script, the JavaScript engine creates a Global Execution Context and pushes it on top of the call stack. Whenever a function is called, the JavaScript engine creates a function execution context for the function, pushes it on top of the call stack, and starts executing the function. If a function calls another function, the JavaScript engine creates a new function execution context for the function that is being called and pushes it on top of the call stack. When the current function completes, the JavaScript engine pops it off the call stack and resumes the execution where it left off. The script will stop when the call stack is empty.

function add(a, b) {
    return a + b;
  }
function average(a, b) {
    return add(a, b) / 2;
  }
  let x = average(10, 20);

When the JavaScript engine executes this script, it places the global execution context (denoted by “main()” or “global()”) function on the call stack JavaScript Call Stack

Resources

Arrow functions in the JavaScript guide Reference page on arrow functions