Week 2 - Functions, Strings, and Control Flow
What is a Function?
Section titled “What is a Function?”Put simply, a function is a series of commands that get bundled together so that they can be run, in that order, once or multiple times.
Functions can be passed information when they are called on to run. They can call other functions to make them run. They can also return some type of resulting value, when needed.
Functions nearly all have a name, just like variables, so you can reference them when you need them to run.
Here are a few examples of what functions can look like.
function hello() { //a basic function declaration}function goodbye(name, message) { //a basic function declaration with two arguments}let open = function () { //an ANONYMOUS function assigned to a variable //known as a function expression};function close(num) { //function declaration with one argument num = num + 1; //and a return value return num;}let next = function (fn) { //function expression that receives one argument //if the argument that was passed in is another function, //then we can call it fn();};
//and this is how we could call each of those functionshello();//call the function `hello`goodbye('Steve', 'See ya later');// pass in two strings to the `name` and `message` argumentsopen();//call the function `open`close(17);//pass a number to the `num` argument in the function `close`next(hello);//pass a reference to another function to the `fn` argument in the function `next`
You can make a function run by writing its name plus a set of parentheses.
Function Declarations and Expressions
Section titled “Function Declarations and Expressions”There are two ways to define your function, with a declaration
or an expression
.
function f1() { //function declaration}const f2 = function () { //function expression};
Both are equally valid ways to define your function. The only important difference is that a declaration
can be called from anywhere in your code. An expression
can only be called from below where
you defined it. This has to do with scope and hoisting, which will explain shortly.
Introduction to Functions
As already mentioned, to call a function and make it run you just have to add a set of parentheses after the name of the function.
An expression
is any single operation that you have in your code. 1 + 3
is an expression. The act of declaring a function is also an expression. Just like in High School math, you can wrap expressions inside parentheses to group terms and control the sequence of operations for multiple expressions.
Expressions cannot go on the left hand side of an equal sign.
Statements vs Expressions
Section titled “Statements vs Expressions”Single lines of code in JS can be either a statement or an expression.
Put briefly, an expression can be placed on the right-hand side of an equal sign.
Statements vs Expressions
This leads to a cool side effect. If we wrap our function declaration in a set of parentheses, it becomes an expression that the JavaScript engine wants to complete before moving on.
function f1() { //a function declaration}f1(); //calling f1 to make it run.
(function f1() { //a function declaration wrapped in parentheses})();//putting the set of parentheses after the expression makes it try to run your newly declared function
By adding a set of parentheses after our function declaration that is wrapped in parentheses we are telling JavaScript to try and run (invoke) the result of the expression.
In other words, we have an Immediately Invoked Function Expression, or IIFE (pronounced if-ee) for short.
If your function expression returns something then that can be assigned to a variable like this:
let result = (function f1() { //IIFE that returns a String which will be assigned to `result` return 'the answer';})();
IIFEs
Return Statements
Section titled “Return Statements”If a function does not contain the return
keyword then, by default, it returns undefined
.
If a function does have a return
keyword then as soon as it is encountered, the function stops running and it returns whatever single value you put after return
.
You are allowed to use multiple return statements in any function. They can all be returning different things. However, only the FIRST return statement that is encountered will actually be executed and the function will stop running at that point.
function f1() { //a simple return statement that returns a string return 'the result';}
function f2(num) { if (num > 10) { return true; //returns true if the value of num is greater than 10 } else { return false; //returns false }}
Function Returns
Function Arguments
Section titled “Function Arguments”An argument is a value that is passed to a function. The goal for writing functions is to make them pure
. This partly means that they should always return the same result if you give them the same
input values. Those input values are the arguments.
By having arguments for our functions, we gain flexibility and reuse. Reuse means writing less code. Less code means completing your work faster and with fewer errors. Imagine you have to write a script that has functions capable of adding together any two numbers between 1 and 10. The inflexible approach would be to write a function for each possible combination. Eg:
function onePlusOne() { return 1 + 1;}function onePlusTwo() { return 1 + 2;}function onePlusThree() { return 1 + 3;}// ... and so on until function tenPlusTen()
So, that would be hundreds of lines of code that take you a long time to write.
Instead we can write ONE function that accepts two arguments that represent the values to be added.
function add(a, b) { return a + b;}
This function is only 3 lines long and can work for ANY combination of numbers, even less than one or greater than 10.
The arguments that we put inside the parentheses are actually variable declarations. We have declared a
and b
just like this would…
function add() { let a; //declared but not assigned a value let b; //declared but not assigned a value}
…but with the added benefit that they will be assigned any values that are passed to the function.
add(3, 5); //calls the add function and assigns 3 to `a` and 5 to `b`
Default Argument Values
Section titled “Default Argument Values”Another cool thing about JavaScript function arguments is how flexible they are. They get declared when you write their names inside the parentheses and just like ALL variables in JavaScript they are automatically given the value undefined
to start. If the function is called then the values passed in are assigned to the available variables.
Using our add
function as an example:
add(3, 4); //3 assigned to `a`, 4 assigned to `b`add(1, 2, 3); //1 assigned to `a`, 2 assigned to `b`, 3 is ignored (sort of)add(5); //5 assigned to `a`, `b` remains undefined
Function declarations have a special keyword called arguments
which is a list of all the values that are passed to the function. If you pass more values to a function that there are available variables, then the values are still available through the arguments
array.
The third line in the code sample above presents our function with a problem. We only sent one value to the function. The variable b
will be left with the default undefined
value. When our function tries to add 5 plus undefined
there will be an error.
Default argument values
are how to prevent this type of error. Below is a new version of our add
function declaration that has default values for the arguments.
function add(a = 0, b = 0) { return a + b;}
Now, we are declaring a
and b
as well as assigning zero as the default value instead of undefined
. If the function gets called with only zero or one argument then no error will occur.
add(); //returns zeroadd(4); //returns 4
Default params
Arrow Functions
Section titled “Arrow Functions”Like most things in programming, there is often a shorter way of writing something. For functions, we have arrow functions. In this simple example you can see a traditional function and then the arrow function equivalent. We drop the keyword function
and add an =
and >
to create the arrow.
const f1 = function (num) { //a traditional function expression return num + 2;};
const f1 = (num) => { //the arrow function equivalent return num + 2;};
So, this might not seem like much difference but it can be shortened even more.
//if the function is on one line you can remove the { } and the `return` keywordconst f1 = (num) => num + 2;
//if there is only one argument then we can remove the ( )const f1 = (num) => num + 2;
//If there is no argument you can write () or _const f2 = () => 1 + 2;const f2 = (_) => 1 + 2; //or this without the ( )
Arrow functions don’t get named. They are written as function expressions and assigned to a variable or passed as a function expression to another function’s argument. Much of the time an arrow function will be used when there is only a single line of code and the function is not going to be used again.
There are a couple other things that change with arrow functions, like the scope of the keyword this
, but we can avoid even having to think about that until much later on.
Arrow Functions
Arrow Function Gotchas
Variable Scope and Hoisting
Section titled “Variable Scope and Hoisting”Scope is the term used to describe where a variable is visible (can be accessed from). With either let
or const
we have the same options for scope. A variable can be in the global
scope or in block
scope. A block scope is created wherever you write { }
. Inside the curly braces is a new block. If a variable is declared inside the curly braces then it is scoped to those curly braces and does not exist outside them.
Functions all (except some arrow functions) have a set of curly braces. So, functions all have their own block scope. There can be other control structures like if statements
or loops
that also create blocks. Each of these blocks is a new scope to declare variables.
Variables that are declared outside of any function are said to be in the global
scope. They are visible anywhere in your code.
Later on we will talk about creating modules with different files. This will add another layer of scope but you will be an expert on scope by the time that we talk about modules.
Block scoped variables only exist while their block is being executed by the JavaScript engine.
let name = 'Bree'; //global variable
function f1() { let age = 25; //block scoped and visible anywhere inside this function if (age > 17) { let isAdulting; //block scoped inside this if statement isAdulting = true; // name, age, and isAdulting are all visible here } //name and age are visible here, but NOT isAdulting}
Variable Scope
Hoisting
Section titled “Hoisting”Hoisting is an effect that happens to variables and functions in JavaScript when the script is read for the first time by the JavaScript engine. When you run a script, it is actually being read twice. Once to identify all the functions and variables and determine their scope. And a second time to execute the code.
Function declarations are hoisted to the top of their scope with the first pass. This is why you can call them from anywhere in the script.
Variable declarations are identified with the first pass. The existence of the variable is hoisted to the top of their scope. They can’t be used from anywhere but the JavaScript engine is aware of their existence. When you get to the line that declares the variable the default undefined
value is assigned to the variable.
So, function expressions can be assigned to variables. The expression itself does NOT get hoisted. The variable name is what gets hoisted to the top of its scope.
// the variables name and f2 are hoisted here but have no value yet// the whole function f1 is hoisted here so it can be called from anywherelet name = 'Joanne';
//function declarationfunction f1(id) { //the variables id and age both have their names hoisted to here //id can be undefined or have a value here console.log(id); let age; //starting here age has the value undefined age = 42;}
let f2 = function () { //function expression. function is NOT hoisted};
Hoisting
Hoisting var vs let
References for Functions
Section titled “References for Functions”- MDN function declaration reference (⌘ + click) to open
- MDN function expression reference (⌘ + click) to open
- MDN Arrow functions (⌘ + click) to open
- MDN default parameter ref (⌘ + click) to open
If Statements
Section titled “If Statements”if statements are a common construct in most programming languages. Simply put, they are a way to let your program make decisions based on questions that have yes - no answers.
if (x == 5) { //notice the two equal signs?}
The example above shows a simple if statement. Inside the parentheses is where you put the question you want the program to ask. Everything and anything that you place inside the parentheses will be boiled down to a yes or no answer.
When asking questions in if statements, comparison operators are used between the values being compared. Greater than >
, less than <
, equal to ==
, greater than or equal to >=
and less than or equal to <=
, are the comparison operators.
Sometimes you just want to know if something exists or has a value equivalent to true
. (See Truthiness below). We can just put a single variable inside the parentheses to check this. We can also add an exclamation mark in front of the variable to check for the opposite.
let x = 5;if (x) { //x is a non-zero number and x is not null or undefined. // read this as "if x"}
if (!x) { //x is zero or undefined or null //we would read this as "if not x"}
Else and Else If
Section titled “Else and Else If”When you need to do things based on both the TRUE and FALSE conditions then you can use an if-else statement.
if (x > 5) { // the condition was true. // run this code} else { // the condition was false // run this code}
MDN reference for comparison operators
At other times you might want to do things based upon multiple possible answers. In these cases we use if {} else if {} else
statements.
if (x == 3) { // if x is equal to 3} else if (x == 4) { //if x is equal to 4} else if (x < 3) { //if x is less than 3} else { //all other possible answers}
You can add as many else if( )
conditions between the if
and the else
statements as you want.
if statements
Two vs Three equal signs
Section titled “Two vs Three equal signs”The examples up to this point have all been using two equal signs. This means that we are comparing the values of the two operands.
There is another comparison operator, three equal signs. It compares the two operands to see if they are actually the same object, not just the same value.
let x = 7;if (x == 7) { //this will be true //the value inside x and the value of the number 7 are equal}
if (x === 7) { //this is also true //the number 7 and the value inside the variable x are the exact same thing}
Up to this point we have only been comparing Primitive values. When dealing with primitives, it will make no difference if you use two or three equal signs. Primitives are just values. When we start comparing Objects, that is when this will matter.
2 vs 3 Equal Signs
Compound If Statements
Section titled “Compound If Statements”There are two logical operators:
&& - AND|| - OR
We can use these inside our if statements to run multiple tests conditions.
You can programmatically ask questions like “is your age over 18 AND
do you like to drink?”.
let beverage = 'Corona';let age = 19;if (age > 18 && beverage == 'Corona') { console.log('You are over 18 and drink Corona');} else { console.log('You are not over 18 OR your beverage is not Corona');}
AND and OR with IF
The alternative to using the logical operators &&
or ||
is to use nested if statements. Here is the alternate version of the above code, using nested if statements.
let beverage = 'Corona';let age = 19;if (age > 18) { if (beverage == 'Corona') { console.log('You are over 18 and drink Corona'); } else { console.log('You are over 18 but do NOT drink Corona'); }} else { console.log('you are not over 18');}
So, depending what you want to do with the result either could be the appropriate choice for your code.
Truthiness
Section titled “Truthiness”Javascript uses the concepts of truthy and falsey. A question may not give you an answer which is exactly TRUE or FALSE. So, there are a handful of things that are considered equal to FALSE. Everything else is considered TRUE.
There are six values that are considered to be falsey
in JavaScript.
let a = 0;//the number zerolet b = false;//the Boolean false valuelet c = '';//an empty stringlet d = null;// a variable that is intentionally set to emptylet e = undefined;// a variable that has been declared but not assigned a value yetlet f = NaN;// Not a Number - the result of Mathematic operations when a non-numeric input was provided
if (a || b || c || d || e || f) { //code here will never run because the values are all Falsey} else { //this code will run}
EVERYTHING else in JavaScript is considered to be truthy. And I mean EVERYTHING. Numbers, Strings, HTML, functions, Arrays, Objects, and anything else is truthy.
Truthy and Falsy
Logical Short-Circuiting
Section titled “Logical Short-Circuiting”Another use for the Logical operators &&
and ||
is in an expression called logical short-circuiting.
This can be like a short hand way of writing an if statement
that has no else clause
and then runs one command if the if statement
is true.
//the if statement versionif (num) { console.log('num has a non-zero value');}
//the logical short circuiting versionnum && console.log('num has a non-zero value');
Logical Short-Circuiting
Ternary Statements
Section titled “Ternary Statements”Ternary statements are used as a short-hand for if else statements
. When you have an if clause
AND and else clause
and there is one command to run for each condition, then you can use a ternary operator.
These are often used to assign one of two possible values to a variable.
The basic syntax requires a ?
and a :
. The expression to the left of the question mark is the question you are asking. Between the question mark and the colon is the value to use or command to run if the question was truthy. The expression that comes after the colon is the value to use or command to run if the question was falsey.
let name = id == 1234 ? 'Elle' : 'Dakota';
You are also allowed to nest one ternary statement inside another, as the expression on either side of the ’:’.
The down-side to using Ternary statements is that they can get very hard to read if you start nesting them.
Ternary Statements
Practical Uses for Ternary Operators
Switch Case Statements
Section titled “Switch Case Statements”If you had an if statement
that was going to compare a variable to a finite list of possible values then a useful alternative to all those parentheses and curly braces might be a switch case
statement.
Let’s say that we have a variable called someName
which contains a name. If the name is one of six possible values then we want to do something specific, tailored to that name. If it is not one of the six then we have a generic thing to do.
We use the keyword case
to provide a comparison value for someName
. Whatever commands that come after a matching case value will run until a break
command is encountered.
You can have a list of possible matches written as a series of case
statements written one after another with no break
between them.
switch (someName) { case 'Alex': //do something specific to Alex //maybe two or three things even. break; case 'Devon': case 'Cara': //do something specific to Devon or Cara break; case 'Riley': //do something specific to Riley //NO break here case 'Cole': case 'Bree': //do something specific to Cole or Bree OR RILEY break; default: //do something generic //this is like the else condition}
Strings
Section titled “Strings”A String is a primitive value made up of letters, numbers, and punctuation, wrapped in quotation marks.
There are three possible quotation marks that you are allowed to use in JavaScript.
" double quotes' single quotes` backtick
The single and double quotes can be used interchangeably, as long as, both the starting and ending mark around the string value are the same.
let name = 'Steve';let last = 'Griffith';
Using the single quotes is considered the current best standard.
The backtick characters were a new addition to core JS as part of the ES6 update in 2015. When you wrap your String in backtick characters it is called a Template String.
What makes them special is that you can embed other variables or expressions inside the String.
let name = 'Steve';let message = `Hello, ${name}. Welcome to MAD9014`;
The variable or expression that gets embedded in the String gets wrapped inside ${ }
.
Template Strings
String Methods
Section titled “String Methods”As we already mentioned, String
s in JavaScript are a Primitive
datatype.
However, JavaScript also has an Object
of type String. When you create a variable and assign a string value to that variable, then JS will quietly create one of these String Objects in the background for you.
This allows us to use the length
property and all the String methods like trim
, indexOf
, split
, toUpperCase
, toLowerCase
, padStart
and many others.
Working with Strings
Concatenating Strings
Section titled “Concatenating Strings”When you need to combine multiple strings or put together strings and variables, there are three ways to do this. With the concatenation operator +
, with the String concat()
method, or by using
Template Strings.
String Concatenation
In JavaScript you will often find that the terms function
and method
are used interchangeably. Here are a series of videos that show examples of the different methods that are available on String Objects.
let str = 'abc'; //abc//assign an initial valuestr = str + 'd'; // abcd//concatenate with + signstr = str.concat('e'); // abcde//concatenate with .concat() methodstr = `${str}f`; // abcdef//concatenate in a template string with backticks
Treat Strings like Arrays
let name = 'Simon Sinek';let third = name[2]; // m//characters in a string are like targeting in an array (list)
SubString and Substr
let str = 'hey there';let sub1 = str.substring(2, 4); //start, end = 'y 'let sub2 = str.substring(2, 3); //start, end = 'y'let sub2 = str.substr(2, 3); //start, length = 'y t'
indexOf and lastIndexOf
let str = 'abcde';let idxc = str.indexOf('c'); // 2let idxa = str.indexOf('a'); // 0let idxy = str.indexOf('y'); // -1
Find and Replace in Strings
let email = 'full.name@work.org';let em1 = email.replace('l', 'L'); // fuLL.name@work.orglet em2 = em1.replace('am', 'AM'); // fuLL.nAMe@work.org
Trimming
let str = ' name@work.org ';let start = str.trimStart(); // 'name@work.org 'let start = str.trimEnd(); // ' name@work.org'let start = str.trim(); // 'name@work.org'
String Padding
let id = '1234';let start = id.padStart(10, '0'); // '0000001234'let start = id.padEnd(10, '0'); // '1234000000'
Split and Join
Here is the full playlist about many of the JavaScript String methods (⌘ + click) to open