---
- [[#JavaScript Fundamentals ]]
- [[#JavaScript Functions, Arrays, Objects, and Loops Notes]]
---
This pasted file mainly teaches basic JavaScript fundamentals: variables, data types, operators, strings, if/else, type conversion/coercion, truthy/falsy values, equality operators, logical operators, switch, expressions/statements, and the ternary operator.
Important first point:
/*
Most of your code is inside block comments like this.
That means JavaScript will ignore it completely.
So if you run this file as-is, most sections will NOT execute.
To test a section, remove the surrounding:
/*
...
*/
But be careful:
Some sections reuse the same variable names like:
const firstName
const age
const birthYear
const now
If multiple sections are uncommented at the same time, you may get errors like:
Identifier 'firstName' has already been declared
This happens because const and let cannot be declared twice in the same scope.
*/let js = "amazing";
console.log(40 + 8 + 23 - 10);
/*
let creates a variable named js.
js stores the string value:
"amazing"
console.log prints something to the console.
40 + 8 + 23 - 10 is calculated first:
40 + 8 = 48
48 + 23 = 71
71 - 10 = 61
So the console prints:
61
*/61console.log("Jonas");
console.log(23);
let firstName = "Matilda";
console.log(firstName);
console.log(firstName);
console.log(firstName);
/*
"Jonas" is a string value.
23 is a number value.
firstName is a variable.
A variable is like a named box/container that stores a value.
Here:
firstName = "Matilda"
So every time we print firstName, JavaScript looks inside the variable and prints:
Matilda
*/Jonas
23
Matilda
Matilda
Matildalet jonas_matilda = "JM";
let $function = 27;
let person = "jonas";
let PI = 3.1415;
let myFirstJob = "Coder";
let myCurrentJob = "Teacher";
let job1 = "programmer";
let job2 = "teacher";
console.log(myFirstJob);jonas_matilda is valid, but in JavaScript camelCase is more common.
Better style:
let jonasMatilda = "JM";
But it is confusing because "function" is a JavaScript keyword. Even though $function works, it is not a good beginner habit.
PI is written in uppercase because it represents a constant-like value.
myFirstJob and myCurrentJob are better names than job1 and job2.
Why?
Because they explain what the values actually mean.
job1 and job2 are vague. myFirstJob and myCurrentJob are clear. */
let myFirstJob = "Coder";
let job1 = "programmer";/* Both work.
But myFirstJob is better because the name explains the purpose.
Good variable names make code easier to understand. */
let javascriptIsFun = true;
console.log(javascriptIsFun);
console.log(typeof javascriptIsFun);
javascriptIsFun = "YES!";
console.log(typeof javascriptIsFun);
/*
javascriptIsFun first stores true.
true is a boolean value.
A boolean has only two possible values:
true
false
typeof tells us the type of a value.
So:
typeof javascriptIsFun
prints: boolean
Then we assign:
javascriptIsFun = "YES!";
Now the same variable stores a string.
JavaScript allows this because it is dynamically typed.
That means the variable itself does not have a fixed type.
The value has the type.
*/true
boolean
stringlet year;
console.log(year);
console.log(typeof year);
year = 1991;
console.log(typeof year);
/*
let year;
This creates the variable, but does not give it a value.
So its value is:
undefined
And its type is also:
undefined
After:
year = 1991;
year now stores a number.
So typeof year becomes:
number
*/undefined
undefined
numberconsole.log(typeof null);
/*
This prints:
object
This is a famous old JavaScript bug.
null means "empty value" or "intentional absence of value".
But typeof null returns "object" because of a historical mistake in JavaScript.
Beginner takeaway:
null is NOT really an object conceptually.
It is an intentional empty value.
*/objectlet age = 30;
age = 31;
/*
let allows reassignment.
First:
age = 30
Then:
age = 31
This is allowed because let variables can be updated.
*/const birthYear = 1991;
// birthYear = 1990;
// const job;
/*
const creates a variable that cannot be reassigned.
This is allowed:
const birthYear = 1991;
This is NOT allowed:
birthYear = 1990;
Because const means the binding cannot point to a new value.
Also, this is NOT allowed:
const job;
A const variable must be initialized immediately.
*/var job = "programmer";
job = "teacher";
/*
var is the older way to declare variables.
It allows reassignment, similar to let.
But var has different scoping rules and can create confusing bugs.
Modern JavaScript usually prefers:
const by default
let when reassignment is needed
avoid var in most new code
*/lastName = "Schmedtmann";
console.log(lastName);
/*
This works in non-strict mode, but it is bad practice.
Why?
Because lastName was not declared using:
let
const
var
JavaScript may create it as a global variable.
That can cause hidden bugs.
Better version:
*/
const lastName = "Schmedtmann";
console.log(lastName);lastName = "Schmedtmann";
/*
Avoid this.
Always declare variables properly:
const lastName = "Schmedtmann";
let age = 30;
*/const now = 2037;
const ageJonas = now - 1991;
const ageSarah = now - 2018;
console.log(ageJonas, ageSarah);
/*
now stores the current example year: 2037.
ageJonas:
2037 - 1991 = 46
ageSarah:
2037 - 2018 = 19
console.log can print multiple values separated by commas.
*/46 19console.log(ageJonas * 2, ageJonas / 10, 2 ** 3);
/*
ageJonas * 2:
46 * 2 = 92
ageJonas / 10:
46 / 10 = 4.6
2 ** 3 means:
2 to the power of 3
2 * 2 * 2 = 8
*/92 4.6 8const firstName = "Jonas";
const lastName = "Schmedtmann";
console.log(firstName + " " + lastName);
/*
+ can add numbers.
But with strings, + joins strings together.
firstName + " " + lastName
becomes:
"Jonas" + " " + "Schmedtmann"
Result:
"Jonas Schmedtmann"
*/Jonas Schmedtmannlet x = 10 + 5; // 15
x += 10; // x = x + 10
x *= 4; // x = x * 4
x++; // x = x + 1
x--; // x = x - 1
x--; // x = x - 1
console.log(x);
/*
Step-by-step:
x = 10 + 5
x = 15
x += 10
x = 15 + 10
x = 25
x *= 4
x = 25 * 4
x = 100
x++
x = 101
x--
x = 100
x--
x = 99
Final value:
99
*/99console.log(ageJonas > ageSarah);
console.log(ageSarah >= 18);
const isFullAge = ageSarah >= 18;
/*
ageJonas is 46.
ageSarah is 19.
ageJonas > ageSarah
means:
46 > 19
true
ageSarah >= 18
means:
19 >= 18
true
isFullAge stores the result of the comparison.
So:
isFullAge = true
*/true
trueconsole.log(now - 1991 > now - 2018);
/*
JavaScript does subtraction first.
now - 1991:
2037 - 1991 = 46
now - 2018:
2037 - 2018 = 19
Then it compares:
46 > 19
true
*/let x, y;
x = y = 25 - 10 - 5;
console.log(x, y);
/*
Subtraction happens first:
25 - 10 - 5
This is calculated left to right:
25 - 10 = 15
15 - 5 = 10
So:
x = y = 10
Assignment happens right to left.
First:
y = 10
Then:
x = y
So both x and y become 10.
*/10 10const averageAge = (ageJonas + ageSarah) / 2;
/*
Parentheses run first.
ageJonas + ageSarah:
46 + 19 = 65
Then:
65 / 2 = 32.5
Without parentheses, division would happen before addition,
which would give a different result.
*/const massMark = 95;
const heightMark = 1.88;
const massJohn = 85;
const heightJohn = 1.76;
const BMIMark = massMark / heightMark ** 2;
const BMIJohn = massJohn / (heightJohn * heightJohn);
const markHigherBMI = BMIMark > BMIJohn;
console.log(BMIMark, BMIJohn, markHigherBMI);
/*
BMI formula:
BMI = mass / height ** 2
For Mark:
massMark / heightMark ** 2
This means:
95 / 1.88 ** 2
For John:
massJohn / (heightJohn * heightJohn)
This is the same idea:
85 / (1.76 * 1.76)
markHigherBMI stores a boolean:
true -> Mark's BMI is higher
false -> Mark's BMI is not higher
*/26.87867813490267 27.44059917355372 falseconst BMIMark = massMark / heightMark ** 2;
/*
The ** operator has high precedence.
So this is treated like:
massMark / (heightMark ** 2)
That is what we want for BMI.
*/const firstName = "Jonas";
const job = "teacher";
const birthYear = 1991;
const year = 2037;
const jonas =
"I'm " +
firstName +
", a " +
(year - birthYear) +
" year old " +
job +
"!";
console.log(jonas);
/*
This builds a string using +.
The expression:
year - birthYear
is inside parentheses so it calculates first.
2037 - 1991 = 46
Final string:
"I'm Jonas, a 46 year old teacher!"
*/const jonasNew = `I'm ${firstName}, a ${year - birthYear} year old ${job}!`;
console.log(jonasNew);
/*
This is a template literal.
Template literals use backticks:
` `
Inside them, you can insert variables or expressions using:
${}
This is cleaner than using many + signs.
${firstName} becomes Jonas.
${year - birthYear} becomes 46.
${job} becomes teacher.
*/I'm Jonas, a 46 year old teacher!
I'm Jonas, a 46 year old teacher!console.log("String with \n\
multiple \n\
lines");
console.log(`String
multiple
lines`);
/*
\n means new line.
The first version uses escape characters.
The second version uses a template literal.
Template literals make multi-line strings much easier to write.
*/String with
multiple
lines
String
multiple
linesconst age = 15;
if (age >= 18) {
console.log("Sarah can start driving license 🚗");
} else {
const yearsLeft = 18 - age;
console.log(`Sarah is too young. Wait another ${yearsLeft} years :)`);
}
/*
if checks a condition.
Condition:
age >= 18
Here:
15 >= 18
false
So the else block runs.
yearsLeft:
18 - 15 = 3
So the message says Sarah must wait 3 more years.
*/Sarah is too young. Wait another 3 years :)const birthYear = 2012;
let century;
if (birthYear <= 2000) {
century = 20;
} else {
century = 21;
}
console.log(century);
/*
century is declared with let because we assign it later.
If birthYear is less than or equal to 2000,
century becomes 20.
Otherwise, century becomes 21.
Here:
2012 <= 2000
false
So:
century = 21
*/21const massMark = 78;
const heightMark = 1.69;
const massJohn = 92;
const heightJohn = 1.95;
const BMIMark = massMark / heightMark ** 2;
const BMIJohn = massJohn / (heightJohn * heightJohn);
console.log(BMIMark, BMIJohn);
if (BMIMark > BMIJohn) {
console.log(`Mark's BMI (${BMIMark}) is higher than John's (${BMIJohn})!`);
} else {
console.log(`John's BMI (${BMIJohn}) is higher than Marks's (${BMIMark})!`);
}
/*
This compares both BMI values.
If Mark's BMI is greater, the if block runs.
Otherwise, the else block runs.
For this test data:
Mark BMI ≈ 27.31
John BMI ≈ 24.19
So Mark's BMI is higher.
*/27.309968138370508 24.194608809993426
Mark's BMI (27.309968138370508) is higher than John's (24.194608809993426)!console.log(`John's BMI (${BMIJohn}) is higher than Marks's (${BMIMark})!`);
/*
Small grammar issue:
Marks's should be Mark's.
Better:
*/
console.log(`John's BMI (${BMIJohn}) is higher than Mark's (${BMIMark})!`);const inputYear = "1991";
console.log(Number(inputYear), inputYear);
console.log(Number(inputYear) + 18);
/*
inputYear is a string:
"1991"
Number(inputYear) converts it into a number:
1991
Important:
Number(inputYear) does not change the original variable.
inputYear is still the string "1991".
So:
Number(inputYear) + 18
becomes:
1991 + 18 = 2009
*/1991 1991
2009console.log(Number("Jonas"));
console.log(typeof NaN);
/*
"Jonas" cannot be converted into a valid number.
So JavaScript gives:
NaN
NaN means:
Not a Number
But weirdly:
typeof NaN
is:
number
Because NaN is a special invalid number value.
*/NaN
numberconsole.log(String(23), 23);
/*
String(23) converts the number 23 into the string "23".
The second 23 is still a number.
In the console, they may look similar,
but internally they are different types.
*/console.log("I am " + 23 + " years old");This uses type coercion.
When + is used with a string, JavaScript converts the number to a string.
So: "I am " + 23 + " years old"
becomes: "I am " + "23" + " years old"
Result: "I am 23 years old"
console.log("23" - "10" - 3);
console.log("23" / "2");
/*
With -, /, and *, JavaScript usually converts strings to numbers.
"23" - "10" - 3
becomes:
23 - 10 - 3 = 10
"23" / "2"
becomes:
23 / 2 = 11.5
*/I am 23 years old
10
11.5let n = "1" + 1; // "11"
n = n - 1;
console.log(n);
/*
First:
"1" + 1
Because + sees a string, it joins them:
"1" + "1" = "11"
So:
n = "11"
Then:
n - 1
The - operator converts "11" into a number:
11 - 1 = 10
So final output is:
10
*/10console.log(Boolean(0));
console.log(Boolean(undefined));
console.log(Boolean("Jonas"));
console.log(Boolean({}));
console.log(Boolean(""));
/*
Falsy values become false when converted to boolean.
Common falsy values:
0
""
undefined
null
NaN
false
Truthy values become true.
"Jonas" is truthy.
{} is truthy, even though it is an empty object.
*/false
false
true
true
falseconst money = 100;
if (money) {
console.log("Don't spend it all ;)");
} else {
console.log("You should get a job!");
}
/*
money is 100.
100 is truthy.
So the if block runs.
*/Don't spend it all ;)let height = 0;
if (height) {
console.log("YAY! Height is defined");
} else {
console.log("Height is UNDEFINED");
}
/*
height is 0.
0 is falsy.
So the else block runs.
But this message is misleading.
height is actually defined.
Its value is just 0.
This is a common beginner bug.
*/Height is UNDEFINEDlet height = 0;
if (height !== undefined) {
console.log("YAY! Height is defined");
} else {
console.log("Height is UNDEFINED");
}
/*
This checks whether height is undefined,
instead of checking whether it is truthy.
Now 0 is accepted as a valid defined value.
*/const age = "18";
if (age === 18) {
console.log("You just became an adult :D (strict)");
}
if (age == 18) {
console.log("You just became an adult :D (loose)");
}
/*
age is the string:
"18"
Strict equality === checks value AND type.
"18" === 18
false
Because one is string and one is number.
Loose equality == allows type coercion.
"18" == 18
true
Because JavaScript converts "18" into 18 before comparing.
*/You just became an adult :D (loose)/*
Prefer === in most real JavaScript code.
Use == only when you intentionally want type coercion.
For beginners:
Use === by default.
*/
const favourite = Number(prompt("What's your favourite number?"));
console.log(favourite);
console.log(typeof favourite);
/*
prompt asks the user for input in the browser.
Important:
prompt always returns a string.
So if the user types:
23
prompt returns:
"23"
Number(...) can convert it to a number if needed:
23
Then typeof favourite becomes:
number
*//*
This code works in browsers.
It may not work in Node.js by default because Node does not have browser prompt().
*/if (favourite === 23) {
console.log("Cool! 23 is an amazing number!");
} else if (favourite === 7) {
console.log("7 is also a cool number");
} else if (favourite === 9) {
console.log("9 is also a cool number");
} else {
console.log("Number is not 23 or 7 or 9");
}
/*
This checks multiple possibilities.
Only one branch runs.
If favourite is 23, the first block runs.
If not, it checks 7.
If not, it checks 9.
If none match, the else block runs.
*/console.log("Cool! 23 is an amzaing number!");
/*
Typo:
amzaing
Better:
*/
console.log("Cool! 23 is an amazing number!");if (favourite !== 23) {
console.log("Why not 23?");
}
/*
!== means strict not equal.
This checks:
Is favourite NOT equal to 23?
If yes, print:
Why not 23?
*/const hasDriversLicense = true;
const hasGoodVision = true;
console.log(hasDriversLicense && hasGoodVision);
console.log(hasDriversLicense || hasGoodVision);
console.log(!hasDriversLicense);
/*
&& means AND.
true && true = true
Both sides must be true.
|| means OR.
true || true = true
At least one side must be true.
! means NOT.
!true = false
*/true
true
falseconst isTired = false;
if (hasDriversLicense && hasGoodVision && !isTired) {
console.log("Sarah is able to drive!");
} else {
console.log("Someone else should drive...");
}
/*
Sarah can drive only if:
hasDriversLicense is true
hasGoodVision is true
isTired is false
Because isTired is false:
!isTired becomes true
So the full condition is:
true && true && true
Result:
true
The if block runs.
*/Sarah is able to drive!const scoreDolphins = (97 + 112 + 80) / 3;
const scoreKoalas = (109 + 95 + 50) / 3;
console.log(scoreDolphins, scoreKoalas);
if (scoreDolphins > scoreKoalas && scoreDolphins >= 100) {
console.log("Dolphins win the trophy 🏆");
} else if (scoreKoalas > scoreDolphins && scoreKoalas >= 100) {
console.log("Koalas win the trophy 🏆");
} else if (
scoreDolphins === scoreKoalas &&
scoreDolphins >= 100 &&
scoreKoalas >= 100
) {
console.log("Both win the trophy!");
} else {
console.log("No one wins the trophy 😭");
}
/*
First calculate averages.
Dolphins:
(97 + 112 + 80) / 3
289 / 3
96.333...
Koalas:
(109 + 95 + 50) / 3
254 / 3
84.666...
Dolphins have a higher score.
But the rule says the winner must also have at least 100.
Dolphins average is below 100.
So no one wins.
*/96.33333333333333 84.66666666666667
No one wins the trophy 😭scoreDolphins > scoreKoalas && scoreDolphins >= 100
/*
Both conditions must be true.
Dolphins must:
1. Beat Koalas
2. Have score at least 100
If either condition is false, Dolphins do not win.
*/const day = "friday";
switch (day) {
case "monday":
console.log("Plan course structure");
console.log("Go to coding meetup");
break;
case "tuesday":
console.log("Prepare theory videos");
break;
case "wednesday":
case "thursday":
console.log("Write code examples");
break;
case "friday":
console.log("Record videos");
break;
case "saturday":
case "sunday":
console.log("Enjoy the weekend :D");
break;
default:
console.log("Not a valid day!");
}
/*
switch compares day against each case.
Here:
day = "friday"
So JavaScript jumps to:
case "friday":
and prints:
Record videos
break stops the switch.
Without break, JavaScript would continue running the next cases too.
*/Record videosif (day === "monday") {
console.log("Plan course structure");
console.log("Go to coding meetup");
} else if (day === "tuesday") {
console.log("Prepare theory videos");
} else if (day === "wednesday" || day === "thursday") {
console.log("Write code examples");
} else if (day === "friday") {
console.log("Record videos");
} else if (day === "saturday" || day === "sunday") {
console.log("Enjoy the weekend :D");
} else {
console.log("Not a valid day!");
}
/*
This does the same job as the switch statement.
switch is often cleaner when checking one variable against many exact values.
if/else is more flexible when conditions are complex.
*/3 + 4;
1991;
true && false && !false;
/*
These are expressions.
An expression produces a value.
3 + 4 produces 7.
1991 produces 1991.
true && false && !false produces false.
*/if (23 > 10) {
const str = "23 is bigger";
}
/*
This is a statement.
A statement performs an action.
An if statement controls whether some code runs.
Important:
You cannot directly place an if statement inside a template literal expression.
*/const me = "Jonas";
console.log(`I'm ${2037 - 1991} years old ${me}`);
/*
Inside ${}, you put expressions.
2037 - 1991 is an expression.
me is also an expression because it produces the value "Jonas".
So this works.
*/const age = 23;
const drink = age >= 18 ? "wine 🍷" : "water 💧";
console.log(drink);
/*
The ternary operator is a shorter if/else expression.
Syntax:
condition ? valueIfTrue : valueIfFalse
Here:
age >= 18
23 >= 18
true
So drink becomes:
"wine 🍷"
*/wine 🍷let drink2;
if (age >= 18) {
drink2 = "wine 🍷";
} else {
drink2 = "water 💧";
}
console.log(drink2);
/*
This does the same thing as the ternary version.
The if/else version is longer.
The ternary version is useful for simple value selection.
Use if/else when the logic becomes bigger or harder to read.
*/console.log(`I like to drink ${age >= 18 ? "wine 🍷" : "water 💧"}`);
/*
Template literals can contain expressions inside ${}.
A ternary operator is an expression.
So it can be used directly inside a template literal.
Since age is 23, this becomes:
I like to drink wine 🍷
*/I like to drink wine 🍷const bill = 430;
const tip = bill <= 300 && bill >= 50 ? bill * 0.15 : bill * 0.2;
console.log(
`The bill was ${bill}, the tip was ${tip}, and the total value ${bill + tip}`
);
/*
The rule:
If bill is between 50 and 300, tip is 15%.
Otherwise, tip is 20%.
Condition:
bill <= 300 && bill >= 50
For bill = 430:
430 <= 300 is false
430 >= 50 is true
false && true = false
So the second value runs:
bill * 0.2
430 * 0.2 = 86
Total:
430 + 86 = 516
*/The bill was 430, the tip was 86, and the total value 516const tip = bill >= 50 && bill <= 300 ? bill * 0.15 : bill * 0.2;
/*
This is the same logic.
But many people find this easier to read:
bill >= 50 && bill <= 300
It reads like:
bill is at least 50 and at most 300
*//*
1. Most code is commented out.
So it will not run until you uncomment it.
2. Many sections reuse variable names.
Example:
const firstName
const age
const birthYear
const now
If you uncomment too many sections at once,
you may get redeclaration errors.
3. Avoid creating variables without let/const/var.
Bad:
lastName = "Schmedtmann";
Better:
const lastName = "Schmedtmann";
4. prompt() works in the browser, not normal Node.js by default.
5. Use === instead of == in most real code.
6. Be careful with truthy/falsy checks.
A value like 0 is falsy,
but that does not mean it is undefined.
*/This code is a strong JavaScript basics practice file. The biggest concepts are:
/*
Variables store values.
let can be reassigned.
const cannot be reassigned.
Avoid var in modern JavaScript.
JavaScript values have types:
number, string, boolean, undefined, null, object, etc.
Operators let you calculate, compare, and assign values.
if/else, switch, and ternary operators help your program make decisions.
Template literals are the clean modern way to build strings.
JavaScript sometimes converts types automatically,
but this can be confusing.
So prefer:
Number(...) for clear conversion
=== for strict comparison
const by default
let only when needed
*/Concise beginner takeaway: JavaScript is flexible, but that flexibility can create confusion, so write clear variables, use **const**/**let**, prefer **===**, and be careful with automatic type conversion.
This code mainly teaches strict mode, functions, arrow functions, arrays, objects, object methods, **this**, loops, **break**, **continue**, and using loops with arrays.
Important first note:
'use strict';
/*
'use strict' activates strict mode.
Strict mode makes JavaScript catch more mistakes.
For example, without strict mode, JavaScript may allow accidental global variables.
With strict mode, some bad patterns become errors instead of silently working.
This helps beginners because mistakes become easier to find.
*/'use strict';
let hasDriversLicense = false;
const passTest = true;
if (passTest) hasDriversLicense = true;
if (hasDriversLicense) console.log('I can drive :D');
/*
hasDriversLicense starts as false.
passTest is true.
This condition runs:
if (passTest)
Since passTest is true, this line runs:
hasDriversLicense = true;
Now hasDriversLicense becomes true.
Then this condition also runs:
if (hasDriversLicense)
So the console prints:
I can drive :D
*/I can drive :D// const interface = 'Audio';
// const private = 534;
/*
These are commented out.
In strict mode, some words are reserved for future JavaScript features.
Examples:
interface
private
So using them as variable names can cause errors.
Strict mode helps prevent you from writing code that may conflict with JavaScript rules.
*/function logger() {
console.log('My name is Jonas');
}
logger();
logger();
logger();
/*
function logger() creates a reusable block of code.
The function body is:
console.log('My name is Jonas');
But the function does not run automatically.
To run it, we call it:
logger();
Calling a function is also called:
- running a function
- invoking a function
- executing a function
Since logger() is called 3 times, the message prints 3 times.
*/My name is Jonas
My name is Jonas
My name is Jonasfunction fruitProcessor(apples, oranges) {
const juice = `Juice with ${apples} apples and ${oranges} oranges.`;
return juice;
}
const appleJuice = fruitProcessor(5, 0);
console.log(appleJuice);
const appleOrangeJuice = fruitProcessor(2, 4);
console.log(appleOrangeJuice);
/*
apples and oranges are parameters.
Parameters are like temporary variables inside the function.
When we call:
fruitProcessor(5, 0)
apples becomes 5.
oranges becomes 0.
The function creates this string:
Juice with 5 apples and 0 oranges.
return sends that value back outside the function.
So appleJuice stores the returned string.
Same with:
fruitProcessor(2, 4)
apples becomes 2.
oranges becomes 4.
*/Juice with 5 apples and 0 oranges.
Juice with 2 apples and 4 oranges.function fruitProcessor(apples, oranges) {
const juice = `Juice with ${apples} apples and ${oranges} oranges.`;
return juice;
}
/*
console.log prints something.
return gives a value back.
They are not the same.
If a function only console.logs, you can see output,
but you cannot easily reuse the result.
If a function returns a value,
you can store it in a variable and use it later.
*/// Function declaration
function calcAge1(birthYeah) {
return 2037 - birthYeah;
}
const age1 = calcAge1(1991);
// Function expression
const calcAge2 = function (birthYeah) {
return 2037 - birthYeah;
};
const age2 = calcAge2(1991);
console.log(age1, age2);
/*
Both functions calculate age.
birthYeah is probably meant to be birthYear.
The typo does not break the code because the parameter name is just a local variable name.
calcAge1 is a function declaration.
calcAge2 is a function expression stored inside a const variable.
Both are called in a similar way:
calcAge1(1991)
calcAge2(1991)
Both return:
2037 - 1991 = 46
*/46 46/*
Function declarations are hoisted.
That means you can call them before they appear in the code.
Function expressions are not usable before the variable is initialized.
So this works:
calcAge1(1991);
function calcAge1(birthYear) {
return 2037 - birthYear;
}
But this does NOT work:
calcAge2(1991);
const calcAge2 = function (birthYear) {
return 2037 - birthYear;
};
Reason:
calcAge2 is a const variable.
It is in the Temporal Dead Zone before initialization.
*/const calcAge3 = birthYeah => 2037 - birthYeah;
const age3 = calcAge3(1991);
console.log(age3);
/*
This is an arrow function.
It is a shorter way to write a function.
Because there is only one parameter, parentheses are optional:
birthYeah => ...
Because there is only one expression, return is automatic:
2037 - birthYeah
So this returns:
2037 - 1991 = 46
*/46const yearsUntilRetirement = (birthYeah, firstName) => {
const age = 2037 - birthYeah;
const retirement = 65 - age;
return `${firstName} retires in ${retirement} years`;
};
console.log(yearsUntilRetirement(1991, 'Jonas'));
console.log(yearsUntilRetirement(1980, 'Bob'));
/*
This arrow function has two parameters:
birthYeah
firstName
Because there are two parameters, we need parentheses:
(birthYeah, firstName)
Because the function has multiple lines, we need curly braces:
{
...
}
When using curly braces in an arrow function,
return is NOT automatic.
So we must write:
return ...
*/Jonas retires in 19 years
Bob retires in 8 yearsconst calcAge3 = birthYeah => 2037 - birthYeah;
const yearsUntilRetirement = (birthYeah, firstName) => {
const age = 2037 - birthYeah;
const retirement = 65 - age;
return `${firstName} retires in ${retirement} years`;
};
/*
Short arrow function:
parameters => expression
Automatically returns the expression.
Multi-line arrow function:
(parameter1, parameter2) => {
statements...
return result;
}
Needs explicit return.
*/function cutFruitPieces(fruit) {
return fruit * 4;
}
function fruitProcessor(apples, oranges) {
const applePieces = cutFruitPieces(apples);
const orangePieces = cutFruitPieces(oranges);
const juice = `Juice with ${applePieces} piece of apple and ${orangePieces} pieces of orange.`;
return juice;
}
console.log(fruitProcessor(2, 3));
/*
cutFruitPieces takes a fruit count and multiplies it by 4.
fruitProcessor receives:
apples = 2
oranges = 3
Then:
applePieces = cutFruitPieces(2)
applePieces = 2 * 4
applePieces = 8
orangePieces = cutFruitPieces(3)
orangePieces = 3 * 4
orangePieces = 12
Then the final juice string is returned.
*/Juice with 8 piece of apple and 12 pieces of orange.const juice = `Juice with ${applePieces} piece of apple and ${orangePieces} pieces of orange.`;
/*
If applePieces is 8, "piece" should be plural.
Better:
const juice = `Juice with ${applePieces} pieces of apple and ${orangePieces} pieces of orange.`;
*/const calcAge = function (birthYeah) {
return 2037 - birthYeah;
};
const yearsUntilRetirement = function (birthYeah, firstName) {
const age = calcAge(birthYeah);
const retirement = 65 - age;
if (retirement > 0) {
console.log(`${firstName} retires in ${retirement} years`);
return retirement;
} else {
console.log(`${firstName} has already retired 🎉`);
return -1;
}
};
console.log(yearsUntilRetirement(1991, 'Jonas'));
console.log(yearsUntilRetirement(1950, 'Mike'));
/*
yearsUntilRetirement calls calcAge inside it.
For Jonas:
birthYeah = 1991
age = 2037 - 1991 = 46
retirement = 65 - 46 = 19
retirement > 0 is true.
So it logs the message and returns 19.
For Mike:
birthYeah = 1950
age = 2037 - 1950 = 87
retirement = 65 - 87 = -22
retirement > 0 is false.
So the else block runs and returns -1.
*/Jonas retires in 19 years
19
Mike has already retired 🎉
-1console.log(yearsUntilRetirement(1991, 'Jonas'));
/*
The function itself does a console.log:
Jonas retires in 19 years
Then the outer console.log prints the returned value:
19
That is why you see both the message and the number.
*/const calcAverage = (a, b, c) => (a + b + c) / 3;
console.log(calcAverage(3, 4, 5));
/*
calcAverage is an arrow function.
It takes 3 scores:
a, b, c
Then it calculates:
(a + b + c) / 3
For:
calcAverage(3, 4, 5)
3 + 4 + 5 = 12
12 / 3 = 4
*/4let scoreDolphins = calcAverage(44, 23, 71);
let scoreKoalas = calcAverage(65, 54, 49);
console.log(scoreDolphins, scoreKoalas);
const checkWinner = function (avgDolphins, avgKoalas) {
if (avgDolphins >= 2 * avgKoalas) {
console.log(`Dolphins win 🏆 (${avgDolphins} vs. ${avgKoalas})`);
} else if (avgKoalas >= 2 * avgDolphins) {
console.log(`Koalas win 🏆 (${avgKoalas} vs. ${avgDolphins})`);
} else {
console.log('No team wins...');
}
};
checkWinner(scoreDolphins, scoreKoalas);
/*
Dolphins average:
(44 + 23 + 71) / 3
138 / 3
46
Koalas average:
(65 + 54 + 49) / 3
168 / 3
56
Rule:
A team wins only if its score is at least double the other team's score.
Dolphins:
46 >= 2 * 56
46 >= 112
false
Koalas:
56 >= 2 * 46
56 >= 92
false
So no team wins.
*/46 56
No team wins...const friend1 = 'Michael';
const friend2 = 'Steven';
const friend3 = 'Peter';
const friends = ['Michael', 'Steven', 'Peter'];
console.log(friends);
/*
Instead of creating separate variables for related values,
we can store them in an array.
An array is an ordered list of values.
friends contains 3 strings:
index 0 -> Michael
index 1 -> Steven
index 2 -> Peter
Important:
Array indexes start at 0, not 1.
*/const friends = ['Michael', 'Steven', 'Peter'];
console.log(friends[0]);
console.log(friends[2]);
console.log(friends.length);
console.log(friends[friends.length - 1]);
/*
friends[0] gives the first element.
friends[2] gives the third element.
friends.length gives the number of elements.
friends.length is 3.
The last element is at:
friends.length - 1
So:
friends[3 - 1]
friends[2]
That gives:
Peter
*/Michael
Peter
3
Peterfriends[2] = 'Jay';
console.log(friends);
// friends = ['Bob', 'Alice'];
/*
This is allowed:
friends[2] = 'Jay';
Even though friends was declared with const.
Why?
const prevents reassigning the variable itself.
It does NOT freeze the array contents.
So this is allowed:
friends[2] = 'Jay';
But this is not allowed:
friends = ['Bob', 'Alice'];
Because that tries to make friends point to a new array.
*/const firstName = 'Jonas';
const jonas = [
firstName,
'Schmedtmann',
2037 - 1991,
'teacher',
friends
];
console.log(jonas);
console.log(jonas.length);
/*
Arrays can store different types of values:
string
number
another array
expressions
variables
Here:
firstName gives "Jonas"
2037 - 1991 gives 46
friends is another array
So jonas is a mixed array.
*/const calcAge = function (birthYeah) {
return 2037 - birthYeah;
};
const years = [1990, 1967, 2002, 2010, 2018];
const age1 = calcAge(years[0]);
const age2 = calcAge(years[1]);
const age3 = calcAge(years[years.length - 1]);
console.log(age1, age2, age3);
const ages = [
calcAge(years[0]),
calcAge(years[1]),
calcAge(years[years.length - 1])
];
console.log(ages);
/*
years[0] is 1990.
years[1] is 1967.
years[years.length - 1] is the last year, 2018.
We pass those values into calcAge.
age1:
2037 - 1990 = 47
age2:
2037 - 1967 = 70
age3:
2037 - 2018 = 19
Then we store these returned values in a new array called ages.
*/47 70 19
[47, 70, 19]const friends = ['Michael', 'Steven', 'Peter'];
const newLength = friends.push('Jay');
console.log(friends);
console.log(newLength);
/*
push adds an element to the end of an array.
Before:
['Michael', 'Steven', 'Peter']
After:
['Michael', 'Steven', 'Peter', 'Jay']
push also returns the new length of the array.
So newLength is 4.
*/friends.unshift('John');
console.log(friends);
/*
unshift adds an element to the beginning of an array.
Before:
['Michael', 'Steven', 'Peter', 'Jay']
After:
['John', 'Michael', 'Steven', 'Peter', 'Jay']
*/friends.pop(); // removes last element
const popped = friends.pop();
console.log(popped);
console.log(friends);
/*
pop removes the last element.
First pop removes:
Jay
Second pop removes:
Peter
The second removed value is stored in popped.
So popped is:
Peter
Now friends contains:
['John', 'Michael', 'Steven']
*/friends.shift();
console.log(friends);
/*
shift removes the first element.
Before:
['John', 'Michael', 'Steven']
After removing John:
['Michael', 'Steven']
*/console.log(friends.indexOf('Steven'));
console.log(friends.indexOf('Bob'));
/*
indexOf tells you the index of a value.
If Steven is found at index 1, it returns:
1
If Bob is not found, it returns:
-1
*/friends.push(23);
console.log(friends.includes('Steven'));
console.log(friends.includes('Bob'));
console.log(friends.includes(23));
/*
includes checks if the array contains a value.
It returns true or false.
includes uses strict checking.
So:
friends.includes(23)
is true if the number 23 exists.
But:
friends.includes('23')
would be false if the array contains number 23, not string "23".
*/if (friends.includes('Steven')) {
console.log('You have a friend called Steven');
}
/*
includes returns a boolean.
If Steven exists in the array, the condition is true.
So the message prints.
*/const calcTip = function (bill) {
return bill >= 50 && bill <= 300 ? bill * 0.15 : bill * 0.2;
};
const bills = [125, 555, 44];
const tips = [
calcTip(bills[0]),
calcTip(bills[1]),
calcTip(bills[2])
];
const totals = [
bills[0] + tips[0],
bills[1] + tips[1],
bills[2] + tips[2]
];
console.log(bills, tips, totals);
/*
calcTip returns:
15% if bill is between 50 and 300
20% otherwise
bills:
125, 555, 44
Tip for 125:
125 * 0.15 = 18.75
Tip for 555:
555 * 0.2 = 111
Tip for 44:
44 * 0.2 = 8.8
totals means bill + tip.
*/[125, 555, 44] [18.75, 111, 8.8] [143.75, 666, 52.8]const jonasArray = [
'Jonas',
'Schmedtmann',
2037 - 1991,
'teacher',
['Michael', 'Peter', 'Steven']
];
const jonas = {
firstName: 'Jonas',
lastName: 'Schmedtmann',
age: 2037 - 1991,
job: 'teacher',
friends: ['Michael', 'Peter', 'Steven']
};
/*
Arrays are ordered lists.
Objects store data using property names.
In jonasArray, you need to remember:
index 0 means first name
index 1 means last name
index 2 means age
In jonas object, the meaning is clear:
firstName: 'Jonas'
lastName: 'Schmedtmann'
age: 46
Objects are better when each value has a clear label.
*/const jonas = {
firstName: 'Jonas',
lastName: 'Schmedtmann',
age: 2037 - 1991,
job: 'teacher',
friends: ['Michael', 'Peter', 'Steven']
};
console.log(jonas.lastName);
console.log(jonas['lastName']);
/*
Both lines access the same property.
Dot notation:
jonas.lastName
Bracket notation:
jonas['lastName']
Dot notation is simpler.
Bracket notation is useful when the property name is calculated or stored in a variable.
*/Schmedtmann
Schmedtmannconst nameKey = 'Name';
console.log(jonas['first' + nameKey]);
console.log(jonas['last' + nameKey]);
/*
'nameKey' stores:
'Name'
So:
'first' + nameKey
becomes:
'firstName'
jonas['firstName'] gives:
Jonas
And:
'last' + nameKey
becomes:
'lastName'
jonas['lastName'] gives:
Schmedtmann
*/Jonas
Schmedtmann// console.log(jonas.'last' + nameKey)
/*
This is invalid.
Dot notation cannot use expressions.
This does NOT work:
jonas.'last' + nameKey
Use bracket notation for computed property names:
jonas['last' + nameKey]
*/const interestedIn = prompt(
'What do you want to know about Jonas? Choose between firstName, lastName, age, job, and friends'
);
if (jonas[interestedIn]) {
console.log(jonas[interestedIn]);
} else {
console.log('Wrong request! Choose between firstName, lastName, age, job, and friends');
}
/*
prompt gets input from the user.
If the user types:
job
then:
jonas[interestedIn]
becomes:
jonas['job']
which gives:
teacher
This only works with bracket notation.
jonas.interestedIn would look for a property literally called interestedIn,
which does not exist.
*//*
prompt works in browsers.
It does not work in normal Node.js by default.
*/if (jonas[interestedIn]) {
console.log(jonas[interestedIn]);
}
/*
This checks truthiness.
It works for this object because all valid values are truthy.
But if a valid property had a value like:
0
false
''
then this condition would incorrectly go to else.
A more precise check would be:
*/
if (interestedIn in jonas) {
console.log(jonas[interestedIn]);
} else {
console.log('Wrong request!');
}jonas.location = 'Portugal';
jonas['twitter'] = '@jonasschmedtman';
console.log(jonas);
/*
You can add new properties after creating an object.
Dot notation:
jonas.location = 'Portugal'
Bracket notation:
jonas['twitter'] = '@jonasschmedtman'
Both add new properties to the object.
*/console.log(
`${jonas.firstName} has ${jonas.friends.length} friends, and his best friend is called ${jonas.friends[0]}`
);
/*
jonas.firstName gives:
Jonas
jonas.friends gives the friends array:
['Michael', 'Peter', 'Steven']
jonas.friends.length gives:
3
jonas.friends[0] gives the first friend:
Michael
Final output:
Jonas has 3 friends, and his best friend is called Michael
*/const jonas = {
firstName: 'Jonas',
lastName: 'Schmedtmann',
birthYeah: 1991,
job: 'teacher',
friends: ['Michael', 'Peter', 'Steven'],
hasDriversLicense: true,
calcAge: function () {
this.age = 2037 - this.birthYeah;
return this.age;
},
getSummary: function () {
return `${this.firstName} is a ${this.calcAge()}-year old ${jonas.job}, and he has ${
this.hasDriversLicense ? 'a' : 'no'
} driver's license.`;
}
};
console.log(jonas.calcAge());
/*
A function inside an object is called a method.
calcAge is a method.
Inside a method, this refers to the object that called the method.
Here:
jonas.calcAge()
So inside calcAge:
this === jonas
Therefore:
this.birthYeah
means:
jonas.birthYeah
which is 1991.
this.age = 2037 - this.birthYeah
creates a new property:
jonas.age = 46
Then it returns 46.
*/46console.log(jonas.age);
console.log(jonas.age);
console.log(jonas.age);
/*
After calling:
jonas.calcAge()
the object now has an age property.
So jonas.age gives:
46
This avoids recalculating the age every time.
Important:
If you try jonas.age before calling jonas.calcAge(),
it would be undefined because the age property has not been created yet.
*/46
46
46getSummary: function () {
return `${this.firstName} is a ${this.calcAge()}-year old ${jonas.job}, and he has ${
this.hasDriversLicense ? 'a' : 'no'
} driver's license.`;
}
/*
getSummary is another method.
this.firstName gives:
Jonas
this.calcAge() calls the calcAge method from the same object.
this.hasDriversLicense ? 'a' : 'no'
means:
if hasDriversLicense is true, use 'a'
otherwise, use 'no'
Since hasDriversLicense is true, it uses:
a
Final sentence:
Jonas is a 46-year old teacher, and he has a driver's license.
*/return `${this.firstName} is a ${this.calcAge()}-year old ${jonas.job}, and he has ${
this.hasDriversLicense ? 'a' : 'no'
} driver's license.`;
/*
This works, but inside the object method it is better to use:
this.job
instead of:
jonas.job
Better:
*/
return `${this.firstName} is a ${this.calcAge()}-year old ${this.job}, and he has ${
this.hasDriversLicense ? 'a' : 'no'
} driver's license.`;
/*
Why?
Using this.job makes the method depend on the current object,
not specifically on a variable named jonas.
*/const mark = {
fullName: 'Mark Miller',
mass: 78,
height: 1.69,
calcBMI: function () {
this.bmi = this.mass / this.height ** 2;
return this.bmi;
}
};
const john = {
fullName: 'John Smith',
mass: 92,
height: 1.95,
calcBMI: function () {
this.bmi = this.mass / this.height ** 2;
return this.bmi;
}
};
mark.calcBMI();
john.calcBMI();
console.log(mark.bmi, john.bmi);
/*
Each object stores:
fullName
mass
height
calcBMI method
When we call:
mark.calcBMI()
this refers to mark.
So:
this.mass means mark.mass
this.height means mark.height
this.bmi creates mark.bmi
Same for john.
BMI formula:
mass / height ** 2
*/27.309968138370508 24.194608809993426if (mark.bmi > john.bmi) {
console.log(`${mark.fullName}'s BMI (${mark.bmi}) is higher than ${john.fullName}'s BMI (${john.bmi})`);
} else if (john.bmi > mark.bmi) {
console.log(`${john.fullName}'s BMI (${john.bmi}) is higher than ${mark.fullName}'s BMI (${mark.bmi})`);
}
/*
mark.bmi is about 27.31.
john.bmi is about 24.19.
So Mark's BMI is higher.
The first if block runs.
*/Mark Miller's BMI (27.309968138370508) is higher than John Smith's BMI (24.194608809993426)/*
You could round the BMI values to make the output cleaner:
*/
console.log(
`${mark.fullName}'s BMI (${mark.bmi.toFixed(1)}) is higher than ${john.fullName}'s BMI (${john.bmi.toFixed(1)})`
);
/*
toFixed(1) shows 1 digit after the decimal.
Example:
27.3
24.2
*/for (let rep = 1; rep <= 30; rep++) {
console.log(`Lifting weights repetition ${rep} 🏋️♀️`);
}
/*
A for loop repeats code.
It has 3 main parts:
let rep = 1
Start rep at 1.
rep <= 30
Keep looping while this is true.
rep++
After each loop, increase rep by 1.
So this prints repetitions from 1 to 30.
*/for (initial value; condition; update) {
// code to repeat
}
/*
The loop keeps running while the condition is true.
When the condition becomes false, the loop stops.
*/const jonas = [
'Jonas',
'Schmedtmann',
2037 - 1991,
'teacher',
['Michael', 'Peter', 'Steven'],
true
];
const types = [];
for (let i = 0; i < jonas.length; i++) {
console.log(jonas[i], typeof jonas[i]);
types.push(typeof jonas[i]);
}
console.log(types);
/*
i starts at 0 because array indexes start at 0.
The loop keeps going while:
i < jonas.length
This means it visits every valid index in the array.
jonas[i] reads the current array element.
typeof jonas[i] gives the type of that element.
types.push(...) adds the type into the types array.
*/Jonas string
Schmedtmann string
46 number
teacher string
['Michael', 'Peter', 'Steven'] object
true boolean
['string', 'string', 'number', 'string', 'object', 'boolean']typeof ['Michael', 'Peter', 'Steven']
/*
This gives:
object
In JavaScript, arrays are a special kind of object.
So typeof array returns "object".
To properly check if something is an array, use:
Array.isArray(value)
*/const years = [1991, 2007, 1969, 2020];
const ages = [];
for (let i = 0; i < years.length; i++) {
ages.push(2037 - years[i]);
}
console.log(ages);
/*
The loop goes through each birth year.
For each year, it calculates:
2037 - year
Then pushes the result into ages.
Step-by-step:
2037 - 1991 = 46
2037 - 2007 = 30
2037 - 1969 = 68
2037 - 2020 = 17
So ages becomes:
[46, 30, 68, 17]
*/[46, 30, 68, 17]console.log('--- ONLY STRINGS ---');
for (let i = 0; i < jonas.length; i++) {
if (typeof jonas[i] !== 'string') continue;
console.log(jonas[i], typeof jonas[i]);
}
/*
continue skips the current loop iteration.
This line means:
If the current value is NOT a string,
skip the rest of this loop round.
So only strings get printed.
Numbers, arrays, and booleans are skipped.
*/--- ONLY STRINGS ---
Jonas string
Schmedtmann string
teacher stringconsole.log('--- BREAK WITH NUMBER ---');
for (let i = 0; i < jonas.length; i++) {
if (typeof jonas[i] === 'number') break;
console.log(jonas[i], typeof jonas[i]);
}
/*
break stops the entire loop.
The loop prints values until it finds a number.
jonas[0] is string -> print
jonas[1] is string -> print
jonas[2] is number -> break
So the loop stops before printing the number.
*/--- BREAK WITH NUMBER ---
Jonas string
Schmedtmann stringconst jonas = [
'Jonas',
'Schmedtmann',
2037 - 1991,
'teacher',
['Michael', 'Peter', 'Steven'],
true
];
for (let i = jonas.length - 1; i >= 0; i--) {
console.log(i, jonas[i]);
}
/*
jonas.length - 1 gives the last valid index.
The array has 6 elements.
So the last index is:
6 - 1 = 5
The loop starts at index 5 and goes down to 0.
i-- means decrease i by 1 after each loop.
*/5 true
4 ['Michael', 'Peter', 'Steven']
3 teacher
2 46
1 Schmedtmann
0 Jonasfor (let exercise = 1; exercise < 4; exercise++) {
console.log(`-------- Starting exercise ${exercise}`);
for (let rep = 1; rep < 6; rep++) {
console.log(`Exercise ${exercise}: Lifting weight repetition ${rep} 🏋️♀️`);
}
}
/*
This is a nested loop.
Outer loop:
exercise = 1, 2, 3
Inner loop:
rep = 1, 2, 3, 4, 5
For every one exercise,
the inner loop runs 5 times.
So total repetitions printed:
3 exercises * 5 reps = 15 rep messages
*/let rep = 1;
while (rep <= 10) {
rep++;
}
/*
A while loop keeps running while the condition is true.
This loop starts with:
rep = 1
Each time, rep increases by 1.
When rep becomes 11, the condition becomes false:
11 <= 10
false
Then the loop stops.
This version does not print anything because console.log is commented out.
*/for (let rep = 1; rep <= 10; rep++) {
console.log(`Lifting weights repetition ${rep} 🏋️♀️`);
}
/*
A for loop is good when you know how many times you want to loop.
Example:
Loop from 1 to 10.
*/let dice = Math.trunc(Math.random() * 6) + 1;
while (dice !== 6) {
console.log(`You rolled a ${dice}`);
dice = Math.trunc(Math.random() * 6) + 1;
if (dice === 6) console.log('Loop is about to end...');
}
/*
A while loop is good when you do NOT know how many times you need to loop.
Here, we keep rolling dice until we roll a 6.
Math.random() gives a random decimal from 0 up to less than 1.
Math.random() * 6 gives a number from 0 up to less than 6.
Math.trunc(...) removes the decimal part.
Then + 1 makes the result between 1 and 6.
*//*
The dice output changes every time you run the program.
Example possible output:
You rolled a 3
You rolled a 1
You rolled a 5
Loop is about to end...
But it could be different every run because Math.random() is random.
*/const calcTip = function (bill) {
return bill >= 50 && bill <= 300 ? bill * 0.15 : bill * 0.2;
};
const bills = [22, 295, 176, 440, 37, 105, 10, 1100, 86, 52];
const tips = [];
const totals = [];
for (let i = 0; i < bills.length; i++) {
const tip = calcTip(bills[i]);
tips.push(tip);
totals.push(tip + bills[i]);
}
console.log(bills, tips, totals);
/*
bills contains 10 bill values.
tips starts empty.
totals starts empty.
The loop goes through every bill.
For each bill:
1. Calculate the tip using calcTip.
2. Push the tip into tips.
3. Push bill + tip into totals.
This is better than manually writing:
calcTip(bills[0])
calcTip(bills[1])
calcTip(bills[2])
because the loop works for any array length.
*/bills:
[22, 295, 176, 440, 37, 105, 10, 1100, 86, 52]
tips:
[4.4, 44.25, 26.4, 88, 7.4, 15.75, 2, 220, 12.9, 7.8]
totals:
[26.4, 339.25, 202.4, 528, 44.4, 120.75, 12, 1320, 98.9, 59.8]const calcAverage = function (arr) {
let sum = 0;
for (let i = 0; i < arr.length; i++) {
sum += arr[i];
}
return sum / arr.length;
};
console.log(calcAverage([2, 3, 7]));
console.log(calcAverage(totals));
console.log(calcAverage(tips));
/*
calcAverage takes an array.
Example:
[2, 3, 7]
sum starts at 0.
Loop steps:
sum = 0 + 2 = 2
sum = 2 + 3 = 5
sum = 5 + 7 = 12
Then:
sum / arr.length
12 / 3 = 4
So the average is 4.
*/4return sum / arr.length;
/*
This works if the array has at least one value.
But if arr is empty:
[]
then arr.length is 0.
sum / 0 gives Infinity or NaN-like bad results depending on the situation.
A safer version could be:
*/
const calcAverageSafe = function (arr) {
if (arr.length === 0) return 0;
let sum = 0;
for (let i = 0; i < arr.length; i++) {
sum += arr[i];
}
return sum / arr.length;
};/*
1. birthYeah is probably a typo.
The code still works because the parameter name can be anything.
But birthYear is clearer.
2. avgDolhins in the challenge text is a typo.
It should be avgDolphins.
3. Many const names are reused.
Examples:
const jonas
const friends
const calcAge
If you uncomment multiple sections together, you may get redeclaration errors.
4. prompt() only works in browsers by default.
It will not work in plain Node.js unless you use another input package.
5. Arrays declared with const can still be mutated.
This is allowed:
friends.push('Jay');
friends[2] = 'Jay';
This is not allowed:
friends = ['Bob'];
6. In object methods, prefer this.property instead of hardcoding the object name.
Better:
this.job
Instead of:
jonas.job
*//*
Functions let you reuse logic.
return gives a value back from a function.
Arrow functions are shorter, but multi-line arrow functions need explicit return.
Arrays store ordered lists of values.
Objects store labeled data using properties.
Methods are functions inside objects.
this usually refers to the object calling the method.
for loops are useful when you know how many times to repeat.
while loops are useful when you repeat until some condition changes.
continue skips one loop round.
break stops the loop completely.
Loops are very powerful with arrays because they let you process many values without repeating code manually.
*/Concise beginner takeaway: functions organize logic, arrays store lists, objects store labeled data, and loops let you repeat work efficiently instead of writing the same code again and again.