Objectives

Functions basics, function parameters & scope

Objectives

Function Basics

  • Define what a function is and how they are essential in programming
  • Create functions using function declarations or function expressions
  • Explain how scope works in JavaScript and compare function, block and global scope
  • Understand what hoisting is and how the JavaScript compiler works when analyzing variables and functions

Function Parameters & Scope

  • Define what a parameter is and why they are essential when writing functions
  • Compare and contrast global and function scope
  • Understand what happens when variables are declared without the var keyword

Function Basics I

What is a function

A function is a repeatable process or procedure. A real world analogy of a function is the brew button on a coffee machine. The coffee machine has inputs (hot water, and coffee grounds), and outputs (hot coffee). When you press the button to brew a pot of coffee, you are starting a process that should return an expected output to you. The same thing is true in programming. A function takes a set of variables as inputs and returns a value as an output.

We have already seen many functions in action. For example, in the array section, we learned about push and pop. In GoMix you created functions that deleted or added songs and playlists.These are all functions that operate on an array. Consider the following example:

var arr = [5,4,3,2,1];
var poppedVal = arr.pop();
console.log(arr);
console.log(poppedVal);

In the example, we are using the pop function. It takes no inputs, and it returns a value which is the last item in the array that has been removed from the array. When you run the code in your console, you'll see the array is now [5,4,3,2] and the value of poppedVal is 1.

Declaring Functions

To be a knowledgeable JavaScript programmer, we need to learn to write our own functions as well. There are multiple ways to write functions in JavaScript. We will cover the differences in more detail later. For now, let's start with one way: a function declaration.

In general, we declare a function in the following way:

function anyNameYouWantForTheFunction() {
  // As many lines of code as you want
}

In general, this type of function syntax consists of four parts:

  1. The function keyword,
  2. The name of the function (in this case, anyNameYouWantForTheFunction),
  3. Any parameters for the function (we'll ignore this for now, but parameters will go inside of the parentheses after the function name),
  4. The function body (the code for the function, which lives inside of the curly braces).

It might seem silly, but it would be good to practice typing this syntax out a few times. You'll be writing functions constantly in JavaScript, so the syntax is something you should commit to muscle memory. Try typing these out in your browser console window:

function myFunction() {
}

function myOtherFunction() {
}

function yetAnotherFunction() {
}

function okayIGetItThisIsTheSyntaxForFunctions() {
}

The functions above aren't very interesting, because none of them have a function body. Let's look at an example of a function that actually does something:

// this is called the function definition - we are ONLY defining the function here
function firstFunction(){
    console.log("I just wrote my first function!");
}

Now we have declared a function called firstFunction, but we have not used the function yet. To execute the code within the function, we must invoke the function. A function is invoked by adding a () after the name of the function:

// to call or invoke the function
firstFunction();

If you run this code in the Chrome console, you will see the output is "I just wrote my first function" and on the next line, undefined. Next, we'll learn where the undefined is coming from.

Returning Values From Functions

In JavaScript, if we do not specifically tell the function to return something, it will return undefined when it is finished executing. So how do we tell a function to return something? We use the return keyword!

// this is called the function definition -
// we are ONLY defining the function here

function firstFunction(){
    return "I just wrote my first function!";
}

// to call or invoke the function

firstFunction(); // now we don't see undefined anymore!

Now our function is returning "I just wrote my first function". To capture that string, let's use a variable:

var returnValue = firstFunction();
console.log(returnValue);

Now in the console, you should see "I just wrote my first function". That is the value that was returned from our function call and that is now saved in the returnValue variable.

Remember, the return keyword can ONLY be used inside of a function. let's take a look at another example.

function secondFunction(){
    return "Hello";
    return "Goodbye";
}

secondFunction(); // "Hello"

We see from this example that the return keyword can only be executed once in a function. Once it is executed, the function is complete and no other lines of code will be executed.

Exercises

For these exercises, create:

  • functions-02.html
  • functions-02.js

And use the developer tools in chrome to run and monitor the script.

functions-02.html

<html>
  <head>
    <title>JavaScript Test Site</title>
    <script src="functions-02.js"></script>
  </head>
  <body>
    <p>Nothing going on yet.</p>
  </body>
</html>

Exercises 1: Function calls

In functions-02.js,

Introduce this object:

const playList = {
  id: '01',
  title: 'Beethoven Sonatas',
  artist: 'Beethoven',
  songs: ['Piano Sonata No. 3', 'Piano Sonata No. 7', 'Piano Sonata No. 10'],
  rating: 4,
};
  • Write a new function called songOuput() which uses a loop to iterate through the songs array and console.log all of the songs. See if you can call this function when you click a link on the html page. The ouput can still be posted to the console.
  • Write another funciton called songOutputReverse() which again uses a loop to iterate in the reverse direction, logging the songs starting at 'Piano Sonata No. 10' and finishing with 'Piano Sonata No. 3'. See if you can call this function when you click a link on the html page. The ouput can still be posted to the console.

If we wanted the output presented in the html page rather than the console we could use the return keyword in our songOutputReverse() function. In html use the following code so that you can see the songs output on the web page:

<div>
  <script>
    document.write(songOutputReverseReturn(""))
  </script>
</div>

Function Basics II

Conditional Logic With Return Statements

Now that we have an idea of how functions work, let's explore a previous topic and see how we can refactor some boolean logic. Let's imagine we want to write a function that returns true if a random number is over .5 - otherwise the function should return false. Here is one way we can write it

function isOverPointFive() {
  if (Math.random() > .5) {
    return true;
  } else {
    return false;
  }
}

This code will work just fine, but remember, the return keyword exits from a function. So if the random number is greater than .5 we will exit the function early and never reach the else condition. So we don't even need the "else" condition! We can refactor our code to look like this:

function isOverPointFive() {
  if (Math.random() > .5) {
    return true;
  }
  return false;
}

Much better! If the number is greater than .5, return true and exit the function. Otherwise just return false.

Finally if we wanted to be really fancy - we could use a ternary operator!

function isOverPointFive() {
  return Math.random() > .5 ? true : false;
}

Simplifying it even further, we can take advantage of the fact that Math.random() > .5 returns true or false. So we don't actually need the ternary operator:

function isOverPointFive(){
  return Math.random() > .5;
}

Exercises

For these exercises, create:

  • functions-03.html
  • functions-03.js

And use the developer tools in chrome to run and monitor the script.

functions-03.html

<html>
  <head>
    <title>JavaScript Test Site</title>
    <script src="functions-03.js"></script>
  </head>
  <body>
    <p>Nothing going on yet.</p>
  </body>
</html>
  • Write a function called myName that logs your full name. Save your full name to a variable inside of the function body, then use console.log to print your name to the console.

    myName(); // if your full name was Elie Schoppik this function would return "Elie Schoppik"
  • Create an array called favoriteFoods which contains the strings "pizza" and "ice cream".

  • Write a function called randomFood. The function should use Math.random to randomly choose a favorite food in your favoriteFoods array to return. For example, your function will return either pizza or ice cream, depending on what you get back from Math.random.

    randomFood(); // either returns "pizza" or "ice cream"
  • Create a variable called numbers which is an array that contains the numbers 1 through 10.

  • Write a function called displayOddNumbers which iterates over the numbers array and console.logs out all of the numbers that are odd. Here is what that might look like:

    displayOddNumbers(); 
    
    // 1
    // 3
    // 5
    // 7
    // 9
  • Write a function called displayEvenNumbers which iterates over the numbers array and console.logs out all of the numbers that are even. Here is what that might look like:

    displayEvenNumbers(); 
    
    // 2
    // 4
    // 6
    // 8
    // 10
  • Create a function called returnFirstOddNumber which iterates over the numbers array and returns the first odd number it finds

    returnFirstOddNumber(); 
    
    // 1
  • Create a function called returnFirstEvenNumber which iterates over the numbers array and returns the first even number it finds

    returnFirstEvenNumber(); 
    
    // 2
  • Create a function called returnFirstHalf which returns the first half of the numbers array

    returnFirstHalf(); 
    
    // [1,2,3,4,5]
  • Create a function called returnSecondHalf which returns the second half of the numbers array

    returnSecondHalf(); 
    
    // [6,7,8,9,10]

Function Parameters & Scope I

Function Parameters

So far our functions have not been taking in any input; they simply are returning an output. So when would we want an input to our functions? Let's imagine we want to calculate the sum of two numbers. If our numbers are 5 and 5, well, that's easy.

5 + 5; // 10

But what happens if we don't know what our numbers are? How could we possibly do this? Better yet, what if we want to do 4 + 6, and 2 + 8 and 7 + 3...we would have to start writing a whole bunch of code that's does basically the same function. This is a great example of when we want to add inputs and use a function. Inputs to a function are called parameters or arguments.

So what does a function look like with parameters? Let's write a function called add that takes in two parameters - number1 and number2 - and returns their sum.

function add(number1, number2){
    return number1 + number2;
}

Now our add function will work for any two numbers that we want to add together. It's important to note that the name of the paramters, number1 and number2, are arbitrary names that we have chosen. If we change the names of the parameters to a and b, the function would do exactly the same thing:

// This function will do the same thing as our previous function
function add(a, b){
    return a + b;
}

Now we can define a function with parameters. Let's see how we invoke that function:

add(4, 6); // returns 10
add(2, 8); // returns 10
add(7, 1); // returns 8

In the example above, we are now invoking the add function with parameters. A parameter can be a literal number like we have above, or we could even use variables:

var num1 = 5;
var num2 = 8;
add(num1, num2);  // returns 13

It is important to understand that the variable names we are using when we invoke the function are not related at all to the variable names we have defined inside of the function. The values of num1 and num2 are being copied into the parameters number1 and number2 that are defined in the function.

Function Scope

Now that we have an idea of what functions do, let's talk about what happens when we define variables inside of functions. To do that, we first need to define what scope is.

MDN defines scope as "The context in which values and expressions are 'visible,' or can be referenced". In JavaScript (before ES2015, which is where we will start), there are only 2 kinds of scope: global scope and function scope.

The important takeaways here are

  1. all variables that are defined outside of functions (and inside of functions without the var keyword) are declared in the global scope, and

  2. all variables defined inside of functions can only be accessed by those functions (and any inner functions).

Let's see an example.

var globalVariable = "I live in the global scope";

function makeNewScope(){
    var functionScopeVariable = "I live in the scope of the makeNewScope function";
}

globalVariable; // "I live in the global scope";
makeNewScope(); // maybe this will define the functionScopeVariable...

functionScopeVariable; // This gives us an error! To be specific, a ReferenceError because the functionScopeVariable is not defined.

What happens when we remove the var keyword?

// Since thise variable declaration is in the global scope, it will
// be a globalVariable with or without the var keyword.  It is a best
// practice to always use the var keyword though.
globalVariable = "I live in the global scope";

function makeNewScope(){
    // You do not want to do this in practice.  You should
    // always defined your variables with the var keyword.
    functionScopeVariable = "What happens now?";
}

globalVariable; // "I live in the global scope"
makeNewScope(); // now this will define the functionScopeVariable!

// The value of the variable will be "What happens now?"
functionScopeVariable;

If we omit the var keyword inside of a function, we actually declare that variable in the global scope. While this may seem like the way to go, this is not best practice. If we need to change some variable in a function, we should at least declare it in the global scope and assign it in a function so that our code is more readable.

var globalVariable = "I live in the global scope";

// we are just declaring the variable now; its value will be set to undefined.
var globalVariableToBeChanged;

function makeNewScope() {
    // Here we are assigning the value "What happens now" to the
    // globalVariableToBeChanged variable.
    globalVariableToBeChanged = "Undefined no more!";
}

globalVariable; // "I live in the global scope"
makeNewScope(); // now this will assign a new value to the globalVariableToBeChanged!

// The value of globalVariableToBeChanged is "Undefined no more!"
globalVariableToBeChanged;

You can read more about scope here.

Exercises

  • Make a function for add, subtract, multiply, and divide. Each of these functions should accept two parameters and return the sum, difference, product and quotient.
add(2,2); // 4
subtract(2,2); // 0
multiply(2,2); // 4
divide(2,2); // 1
  • Write a function called sayHello that takes in a string as a parameter. If the parameter passed to the function is your first name, it should return "Hello Boss", but if the parameter passed to the function is any other name, it should return the string "Hello" and the name parameter.
// for this example, my first name is Tim
sayHello("Tim"); // "Hello Boss"
sayHello("Janey"); // "Hello Janey"
sayHello("Elie"); // "Hello Elie"
  • Write a function called average which accepts an array as a parameter. The function should return the average of all of the numbers in the array (you can assume that the array passed to the function will contain only numbers)
average([1,2,3,4,5]); // 3
average([1,2,3,4,5,6]); // 3.5
average([10,20]); // 15
  • Write a function called createStudent, which accepts two parameters both of which are strings. The function should return an object with the keys firstName and lastName and the values should be each of the
createStudent("Elie", "Schoppik");
/*
{
    firstName: "Elie",
    lastName: "Schoppik"
}
*/
createStudent("Tim", "Garcia");
/*
{
    firstName: "Tim",
    lastName: "Garcia"
}
*/
  • Using your createStudent function, create three students and save them each in a variable. Then create a variable called students, which is an array that will store your three students
var tim = createStudent("Tim", "Garcia");
var matt = createStudent("Matt", "Lane");
var elie = createStudent("Elie", "Schoppik");

var students = [tim, matt, elie];

// your students array should contain three objects each with the keys of firstName and lastName. If they do not - make sure you correctly implement the createStudent function from above!
  • Write a function called findStudentByFirstName, which accepts one parameter, a string. This function should iterate through the students array you just made and if the parameter passed to the function is the same as one of the first name's of the students, the function should return true. Otherwise it should return false. This function should be case insensitive so that you can search successfully regardless of capitalization
findStudentByFirstName('elie') // true
findStudentByFirstName('Elie') // true
findStudentByFirstName('Janey') // false
findStudentByFirstName('Janey') // false
findStudentByFirstName('TIM') // true
findStudentByFirstName('MMMaaaTTTtttTTT') // false
  • Write a function called extractEveryThird which accepts an array as a parameter. The function should iterate over the array and return a new array with every 3rd element in the array passed to the function.
extractEveryThird([1,2,3]); // [3]
extractEveryThird([1,2,3,4,5,6]); // [3,6]
extractEveryThird(["a","b","c","d"]); // ["c"]
extractEveryThird(["first value", "second value", "third value"]); // ["third value"]
  • Write a function called countEvensAndOdds which accepts an array as a parameter. This function should return an object with the count of even numbers and the count of odd numbers. The object returned should have the keys oddCount and evenCount.
countEvensAndOdds([1,2,3,4]);
/*
 {
    oddCount:2,
    evenCount:2
 }
*/
countEvensAndOdds([1,2,3,4,5,6,7]);
/*
 {
    oddCount:4,
    evenCount:3
 }
*/
  • In the following example, what will be printed in the console? Make sure you first try read this code before pasting it into the console :)
var myVar = "Hello from global";

function scopePractice() {
   var myVar = "Hello from function scope";
}

scopePractice();
console.log(myVar);

var tricky = "Hello from global";

function trickyScopePractice() {
    tricky = "Hello from function scope";
}

console.log(tricky);

Optional Bonus

  • Write a function called onlyCapitalLetters which accepts a string and returns a new string with only the capital letters passed to the string.
onlyCapitalLetters("Amazing") // "A"
onlyCapitalLetters("nothing") // ""
onlyCapitalLetters("EVERYTHING") // "EVERYTHING"

Solutions

You can find the solutions here

Step 03 Solutions

myName

function myName(){
    var myName = 'Elie Schoppik';
    console.log(myName);
}

randomFood

var favoriteFoods = ['pizza', 'ice cream'];
function randomFood(){
    // lets find a random number between 0 and 1 and multiply it by the length of the array. This will give us a number between 0 and 2. If we always round down, we will get either 0 or 1, so we can use Math.floor to round down.
    var randomIndex = Math.floor(Math.random() * favoriteFoods.length);
    console.log(favoriteFoods[randomIndex]);
}

displayOddNumbers

var numbers = [1,2,3,4,5,6,7,8,9,10];
function displayOddNumbers(){
    for(var i = 0; i < numbers.length; i++){
        // if the value we are at in the array is not divisible by 2 (it's an odd number)
        if(numbers[i] % 2 !== 0){
            // print out that value!
            console.log(numbers[i]);
        }
    }
}

displayEvenNumbers

var numbers = [1,2,3,4,5,6,7,8,9,10];
function displayEvenNumbers(){
    for(var i = 0; i < numbers.length; i++){
        // if the value we are at in the array is divisible by 2 (it's an even number)
        if(numbers[i] % 2 === 0){
            // print out that value!
            console.log(numbers[i]);
        }
    }
}

returnFirstOddNumber

var numbers = [1,2,3,4,5,6,7,8,9,10];
function returnFirstOddNumber(){
    for(var i = 0; i < numbers.length; i++){
        if(numbers[i] % 2 !== 0){
            // print out that value, using return gets us out of the function!
            return numbers[i];
        }
    }
}

returnFirstEvenNumber

var numbers = [1,2,3,4,5,6,7,8,9,10];
function returnFirstEvenNumber(){
    for(var i = 0; i < numbers.length; i++){
        if(numbers[i] % 2 === 0){
            // print out that value!
            return numbers[i];
        }
    }
}

returnFirstHalf

var numbers = [1,2,3,4,5,6,7,8,9,10];
function returnFirstHalf(){
    return numbers.slice(0,numbers.length/2);
}

returnSecondHalf

var numbers = [1,2,3,4,5,6,7,8,9,10];
function returnSecondHalf(){
    return numbers.slice(numbers.length/2);
}

JS Functions Exercise Solutions

add

function add(num1,num2){
    return num1 + num2;
}

subtract

function subtract(num1,num2){
    return num1 - num2;
}

multiply

function multiply(num1,num2){
    return num1 * num2;
}

divide

function divide(num1,num2){
    return num1 / num2;
}

sayHello

var myFirstName = "Elie";
function sayHello(str){
    if(str === myFirstName){
        return "Hello Boss";
    }
    return "Hello " + str;
}

average

function average(arr){
    var total = 0;
    for(var i = 0; i < arr.length; i++){
        total += arr[i];
    }
    return total / arr.length;
}

createStudent

function createStudent(firstName, lastName){
    return {
        firstName: firstName,
        lastName: lastName
    }
}

findStudentByFirstName

// let's first create some students
var tim = createStudent("Tim", "Garcia");
var matt = createStudent("Matt", "Lane");
var elie = createStudent("Elie", "Schoppik");

var students = [tim, matt, elie];

function findStudentByFirstName(name){
    var lowerCasedName = name.toLowerCase();
    for(var i = 0; i < students.length; i++){
        if(students[i].firstName.toLowerCase() === lowerCasedName){
            return true;
        }
    }
    return false;
}

extractEveryThird

function extractEveryThird(arr){
    var newArr = [];
    for(var i = 2; i < arr.length; i += 3){
        newArr.push(arr[i]);
    }
    return newArr;
}

countEvensAndOdds

function countEvensAndOdds(arr){
    var countObj = {
        oddCount: 0,
        evenCount: 0
    }
    for(var i = 0; i < arr.length; i++){
        if(arr[i] % 2 === 0){
            countObj.evenCount++;
        } else {
            countObj.oddCount++;
        }
    }
    return countObj;
}

scope practice

// the first console.log(myVar) outputs "Hello from global"

// the second console.log(myVar) also outputs "Hello from global" (the trickyScopePractice function was not called!)

onlyCapitalLetters

function onlyCapitalLetters(str){
    var newStr = '';
    for(var i = 0; i < str.length; i++){
        if(str[i].charCodeAt(0) < 91 && str[i].charCodeAt(0) > 64 ){
            newStr += str[i];
        }    
    }
    return newStr;
}