Logic & Control Flow
📚 Table of Contents |
---|
if / else |
switch statements |
for loops |
while loops |
for...of loops |
for...in loops |
try... catch |
Intro
- computers read code / scripts the same way humans do (in english anyway), left to right and top to bottom
- control flow (opens in a new tab) is the order in which the computer executes statements in a script
- you control the flow with "control structures", which is a fancy term for things like
if / else statements
,loops
, andfunctions
- this stuff is so common that you have already even seen a lot of this in previous chapters
- aside from sneaking in little
if / else statements
here and there, we have already gone through the operators. here is where you use them and they can start to really make sense
- aside from sneaking in little
- I'm going to show a lot here but know that you can really do a ton with essentially just using
if / else
statements andfor loops
; you can even jump in and start solving leetcode problems
if / else statements
- very often referred to as conditional statements
- all general, modern programming languages (like Python, Java, C++, etc.) all use if / else statements
- the basic logic is pretty simple: "if this thing is true, do this stuff"
- the syntax is to use the
if
keyword (in lowercase), put the condition you are testing in parentheses then the code to run in curly braces:
if (condition) {
// if condition is true, this code will run
}
if (5 < 10) {
console.log("Yes, 5 is less than 10");
}
- the
if
statement can definitely stand alone but very oftenelse
is tacked on to handle if the condition is false
if (condition) {
// if condition is true, this code will run
} else {
// if condition is false, this code will run
}
if (5 > 10) {
console.log("Yes, 5 is greater than 10"); // this won't run bc the condition is false
} else {
console.log("No, 5 is not greater than 10"); // this will run bc the condition is false
}
- in the comparison operators section, I showed the ternary (
?
) operator. I mentioned that is how you do if / else logic on one line. to be 100% honest, not everyone is a fan of ternary statements, sometimes they can be a little harder to read at a glance than regular if / else statements but they are very common in React so I do think it is good to be familiar and able to read them even if you prefer to write regular if / else statements- I like to read them like "is this thing true? if yes, do this, if no do that"
if (isAuthenticated) {
logInUser();
} else {
signUpUser();
}
// these are the exact same
isAuthenticated ? logInUser() : signUpUser();
- if you need to test more than one condition, you can use
else if
statements - you can use as many
else if
statements are you want - you don't see
else if
a ton in professional code bases. in fact r/programminghumor (opens in a new tab) loves to throw jabs at code with tons ofelse if
statements, but sometimes they can help get the job done
if (condition1) {
// this code will run if condition1 is true
} else if (condition2) {
// this code will run if condition1 is false and condition2 is true
} else {
// this code will run if both conditions are false
}
if (size > 100) {
console.log("Big");
} else if (size > 20) {
console.log("Medium");
} else if (size > 4) {
console.log("Small");
} else {
console.log("Tiny");
}
switch statements
- a
switch statement
is the cleaner way to write code that might have a lot ofif else
statements or if you want to check one condition against many values switch statements
offer a way to simplify complex conditional logic where multiple conditions lead to different outcomes based on the same variable or expression- a
switch
statement compares something against multiplecase
values and executes code associated with the first matchingcase
switch (expression) {
case value1:
// code to run when expression equals value1
break;
case value2:
// code to run when expression equals value2
break;
// you can add as many cases as you need
default:
// code to run if no case matches the expression
}
- lets
break
(🙃) that down a little:- the expression is evaluated once at the beginning of the switch statement
- each case is checked against the value of expression
- if a case matches, the code block following that case is executed
- the
break
statement prevents the code from running into the next case. if there is nobreak
statement, the code will keep running and the next case will be checked - the
default
case is optional and runs if no matching case is found. think of it as theelse
in anif/else
statement
switch (animal) {
case "Cheetah":
console.log("very fast");
break;
case "Rabbit":
console.log("pretty fast");
break;
case "Snail":
console.log("slow");
break;
default:
console.log("unknown speed");
}
for loops
- I'm going to try and break this down as simple as I can. when you first start coding, loops in general can be confusing. there are a bunch of different kinds of loops but the
for loop
is where you start - in most programming langaues (JavaScript, Python, C#, Java, Ruby, etc.) most data types/structures (like strings and arrays) are iterable, meaning you can return their elements one at a time
- in most of those languages, you can actually grab the individual elements with the same syntax too; the square brackets with the index you want inside:
[index]
- important note: in almost all programming languages, including JavaScript, iterables are 0 indexed. meaning the first element will be at index 0, NOT 1
grabShitBytheIndex.js
// say you have a string
"Converge";
// to grab the element you want with the [] and the index inside
"Converge"[0]; // grabs the C
"Converge"[1]; // grabs the o
"Converge"[2]; // grabs the n
"Converge"[3]; // grabs the v
// you figure out the rest
// setting the string to a variable does the exact same thing
const aCoolBand = "Converge";
aCoolBand[0]; // grabs the C
aCoolBand[1]; // grabs the o
aCoolBand[2]; // grabs the n
// arrays work the same way
const someCoolBands = ["Quicksand", "Rival Schools", "Gorilla Biscuits"];
someCoolBands[0]; // grabs Quicksand
someCoolBands[1]; // grabs Rival Schools
someCoolBands[2]; // grabs Gorilla Biscuits
- a
for loop
iterates or loops over each element for you so you can access all the elements in the thing you are looping over - syntax:
for (initialExpression; condition; updateExpression) {
// code block to be executed
}
- initialExpression: initializes one or more loop counters. executed once before the loop starts
- condition: the loop runs as long as this condition evaluates to true
- updateExpression: updates the loop counter(s) after each iteration of the loop
for (let i = 0; someCoolBands.length; i++) {
console.log(someCoolBands[i]);
}
- that for loop will give you this in the console:
Quicksand
Rival Schools
Gorilla Biscuits
- kinda tight right? the
for loop
gives you access to each element individually so you can pick the ones you want or don't want with other kinds of logic. if you are given thesomeCoolBands
array, you can now answer questions and do things like tell if there are any bands that start with Q, or any band names that have two words, maybe rearrange them alphabetically, etc. - back to the syntax so everything is crystal clear:
- the
for loop
takes 3 expressions separated by semi-colons (;
) - the first one is that initialExpression. in our example we used
let i = 0;
, which is creating a variable namedi
and set it to0
. you can name this whatever you want but it is common/best practice to usei
forindex
(or use the wordindex
to be super clear in your code). also for the record you can initiate as many variables/values here as you want or need but that is pretty rare to see in the wild and can start to make your code rough to read - then we have the condition, which determines how long the loop will run. you can use whatever kind of logic you want or need here. you can do things like
i < 10
, which would be like telling the for loop to "run as long as i is less than 10". it is very common to use the.length
property like we did in the example. you can use.length
on arrays (opens in a new tab) and strings (opens in a new tab). when you use.length
, you are telling the loop to run as long as thing is that you are iterating over - then finally you have the updateExpression. the third expression updates that first variable we created after every iteration. you will usually see what we used in our example,
i++
, we saw this at the bottom of the arithmetic operators section.++
will simply add 1 to the variable. so the index starts at[0]
, then increments to[1]
and so on. if you were creating a reversefor loop
you could decrement withi--
- so in our example, in plain english: we opened a for loop, we created a variable for the index that is set to 0, we set the loop to iterate over the array's length and increment the index each time
- the
- ok cool, I hope you are with me so far. if not, thats ok, the more you see this kind of stuff the more it will make sense
- to make code a little more readable to yourself and others, it is super common practice to set the element[i] to a variable like this:
for (let i = 0; someCoolBands.length; i++) {
let band = someCoolBands[i];
console.log(band);
}
- this will print the same thing as above to the console. while it is cleaner, you have to know that variables declared inside the
for loop
are only availble inside the loop. that is actually calledscope
and applies to things like other loops and functions too
while loops
while loops
do pretty much the same thing asfor loops
, they iterate over something while a condition is true
while (condition) {
// code block to be executed
}
for loops
are usually little more straight forward but there are some reasons to usewhile loops
instead- off the bat, they are a little cleaner, instead of the 3 statements you only need one
- they are useful when you don't know how many iterations you will need
- they are often used for continuous checks where the condition involves real-time data or other external conditions
- the coolest and maybe most useful reason to use a
while loop
over afor loop
is that you can increment and decrement an index within the loop
let i = 0;
while (i < 10) {
if (someCondition) {
i++;
} else {
i--;
}
}
do... while
- gonna be 100% honest, you won't see this a lot and probably won't write it a lot but if you are reading this, you are doing the deep dive with me so fuck it
- the
do...while
is a variant of thewhile loop
. it creates a loop that executes a specified statement until the test condition evaluates to false. the condition is evaluated after executing the statement, which means the code in thedo
block will execute at least once
do {
// code block to be executed
} while (condition);
do...while
loops are sometimes used in game logic where something will happen at least once and then maybe again based on the user's decisions- its also probably worth noting that
do...while
loops are notorious for causing infite loops if the condition is never found to be false. this can crash your script or even computer
for... of loops
- this one is even more similar to the "regular" for loop, it does the exact same thing except you get your variable name off the jump and don't mess around with defining and incrementing/decrementing your
index
- sometimes you will need access to that
index
, that is when you use a regularfor loop
, if you don't thenfor... of
is a really clean way to iterate over things
// syntax
for (variable of iterable) {
// code block to be executed
}
for (let band of someCoolBands) {
console.log(band);
}
// for... of is pretty common for iterating over strings
const word = "Oasis";
for (let char of word) {
console.log(char);
}
- open the for of loop, define your variable (you can use
let
orconst
), of, then the thing you are iterating over
for... in loops
- the last loop is for iterating over objects
- peep the objects section if you need a little refresher
- objects have
keys
andvalues
andfor... in loops
give you access to both
// syntax
for (key in object) {
// code block to be executed
}
// an object
const spiderMan = {
name: "Peter Parker",
hometown: "Queens, NYC",
occupation: "Photographer",
superPower: "Spider-sense",
girlFriend: "Mary Jane Watson",
nemesis: "Green Goblin",
affiliation: "Avengers",
costumeColor: "Red and Blue",
};
for (let key in spiderMan) {
console.log(key); // access the keys
console.log(spiderMan[key]); // access the values
}
- super similar to the
for... of loop
, open the for loop, define your variable, in, then the object you are iterating through - you access the keys with the variable you define. you can name this whatever you want but here naming this "key" might help your sanity
- access the values with
object[key]
. "object at key is the value" - I'm not sure if this makes things more convenient or a little more confusing (maybe both 🙃) but
for... in loops
can also iterate over arrays- this is not common or recommended if the array's order is important and it is not really as clear as using a regular
for loop
orfor...of loop
, but it is kind of cool that you can access the indecies and the elements in arrays this way if you want
- this is not common or recommended if the array's order is important and it is not really as clear as using a regular
for (let x in someCoolBands) {
console.log(x); // access the indecies
console.log(someCoolBands[x]); // access the elements
}
try... catch
- errors are going to happen. its part of the game. the best coders encounter errors all the time, especially because sometimes they are caused by external factors like calling an API that you don't have control over
try... catch
statements are how you handle these errors gracefully (instead of letting your app crash or having a broken UI)- the idea is pretty straight forward, you open a
try
block, write your code that might have the error occur and then you have thecatch
after to handle the error. by handle the error, I mean you can do things like show the user that something went wrong, create some fallback logic, log the error for yourself, etc
try {
// code to try
console.log("success!");
} catch (error) {
// handle the error
console.log("🚨 something went wrong" + error);
}
try... catch... finally
- you won't see this as often but there is an optional third block you can tack onto the end of a
try... catch
that will run regardless if there was an error or not, that is thefinally
block. so its technically atry... catch... finally
statement - I like to use
try... catch... finally
with things like loading animations. With a loading animation, you will want the loader (maybe a spinner) to run while the user waits for the computer to run the code and then you will want the loader to stop to either show the success or failure (error)
// set loading spinner to true while code runs
loadingSpinner(true);
try {
// code to try
console.log("success!");
} catch (error) {
// handle the error
console.log("🚨 something went wrong" + error);
} finally {
// do this no matter what
loadingSpinner(false);
}
throw
- so, JavaScript is pretty good at giving you errors. they are usually pretty helpful to help you find out wtf went wrong
- technically that is called "throwing an error" or "throwing an exception", same thing
- JS allows you to
throw
your own custom errors - I'm showing this here because if you are going to throw your own custom errors, its a good idea to do it inside of a
try... catch
block... but you also don't have to
function checkAge(age) {
if (age < 18) {
throw new Error("Access denied - you are too young!");
} else {
console.log("Access granted");
}
}
try {
checkAge(15);
} catch (error) {
console.log(error.message);
}