Skip to content

Mastering JavaScript Loops β€” Hogwarts Edition πŸ§™β€β™‚οΈπŸ§™β€β™€οΈ ​

Welcome to the magical world of JavaScript! Today, we'll embark on an enchanting journey through loops, guided by the students of Hogwarts School of Witchcraft and Wizardry. Get ready to explore different types of loops and deepen your understanding of arrays and objects, all set in the wizarding world. Let's dive into spells, potions, and code! πŸͺ„βœ¨

The Marauder's Map of Loops ​

Imagine you're handed the Marauder's Map, and you want to explore every nook and cranny of Hogwarts. Similarly, in programming, loops allow us to traverse data structures efficiently.

Consider an array representing the scores of Harry, Ron, and Hermione in their Defense Against the Dark Arts exam:

javascript
const scores = [85, 75, 95];

How can we iterate over these scores to see each one?

The Classic for Loop ​

The classic for loop gives us precise control over the iteration process.

javascript
for (let index = 0; index < scores.length; index++) {
  console.log(`Student ${index + 1} scored`, scores[index]);
}

What does this loop do?

  • Initialization: let index = 0 starts at the first element.
  • Condition: index < scores.length ensures we don't go out of bounds.
  • Increment: index++ moves to the next element each time.

Output ​

Student 1 scored 85
Student 2 scored 75
Student 3 scored 95

The for...in Loop ​

Suppose you want to focus on the indices rather than the values. The for...in loop is perfect for this.

javascript
for (let index in scores) {
  console.log(`Student ${parseInt(index) + 1} scored`, scores[index]);
}

Does this produce the same result? Yes, but with less code to manage the index.

The for...of Loop ​

When you care about the values themselves and not the indices, the for...of loop is your friend.

javascript
for (let score of scores) {
  console.log("A student scored", score);
}

This loop directly gives you each score.

Output ​

A student scored 85
A student scored 75
A student scored 95

The House Points Hourglass ​

The house points at Hogwarts determine the winner of the House Cup. Let's represent the current points:

javascript
const housePoints = {
  Gryffindor: 150,
  Slytherin: 200,
  Ravenclaw: 180,
  Hufflepuff: 170,
};

How can we iterate over this object to see each house's points?

Iterating Over Objects with for...in ​

The for...in loop is ideal for objects.

javascript
for (let house in housePoints) {
  console.log(`${house} has ${housePoints[house]} points`);
}

But what if we tried using a for...of loop?

javascript
// This will cause an error
for (let house of housePoints) {
  console.log(`${house} has ${housePoints[house]} points`);
}

Don'ts

The for...of loop cannot be used directly on objects. It works on iterable objects like arrays, strings, etc.

Accessing Object Properties ​

There are two ways to access properties in an object:

Dot Notation ​

javascript
console.log(housePoints.Gryffindor); // 150

Bracket Notation ​

javascript
console.log(housePoints["Gryffindor"]); // 150

Which one should you use?

  • Dot Notation: When the property name is a valid identifier.
  • Bracket Notation: When the property name contains spaces or special characters.

The Order of Iteration ​

Do you know in what order the for...in loop iterates over object properties?

TIP

JavaScript does not guarantee the order of object properties in a for...in loop. If the order matters, consider using an array of keys.

Task: Determining the House Cup Winner ​

Loop over the housePoints object to find out which house has the highest points and declare the winner.

Task

  • Loop through each house in housePoints.
  • Keep track of the highest points and the corresponding house.
  • Display the winner at the end.
Reveal Solution
javascript
let highestPoints = 0;
let winningHouse = "";

for (let house in housePoints) {
  if (housePoints[house] > highestPoints) {
    highestPoints = housePoints[house];
    winningHouse = house;
  }
}

console.log(
  `The winner of the House Cup is ${winningHouse} with ${highestPoints} points!`
);

Output ​

The winner of the House Cup is Slytherin with 200 points!

The Wand Collection β€” Arrays of Objects ​

Ollivander's shop has a collection of wands, each with different properties.

javascript
const wands = [
  { core: "Phoenix Feather", wood: "Holly", owner: "Harry Potter" },
  { core: "Dragon Heartstring", wood: "Yew", owner: "Tom Riddle" },
];

How can we add more wands to this collection?

Combining Arrays ​

Suppose new wands have arrived:

javascript
const newWands = [
  { core: "Unicorn Hair", wood: "Willow", owner: "Ron Weasley" },
  { core: "Dragon Heartstring", wood: "Vine", owner: "Hermione Granger" },
];

We can combine the arrays using the spread operator:

javascript
const allWands = [...wands, ...newWands];

Now, allWands contains all the wands.

Iterating Over Arrays of Objects ​

How can we list all wand owners and their wand details?

javascript
for (const wand of allWands) {
  console.log(
    `${wand.owner}'s wand is made of ${wand.wood} with a ${wand.core} core.`
  );
}

Output ​

Harry Potter's wand is made of Holly with a Phoenix Feather core.
Tom Riddle's wand is made of Yew with a Dragon Heartstring core.
Ron Weasley's wand is made of Willow with a Unicorn Hair core.
Hermione Granger's wand is made of Vine with a Dragon Heartstring core.

Task: Calculating the Total Value of Potion Ingredients ​

You're helping Professor Snape manage his potion inventory. Each ingredient has a price and quantity.

javascript
const ingredients = [
  { name: "Bezoar", price: 10, quantity: 2 },
  { name: "Unicorn Horn", price: 20, quantity: 1 },
];

How can we calculate the total value of the inventory?

Task

  • Loop over the ingredients array.
  • For each ingredient, multiply the price by the quantity.
  • Sum up the total value.
Reveal Solution
javascript
let totalValue = 0;

for (const { price, quantity } of ingredients) {
  totalValue += price * quantity;
}

console.log(`The total inventory value is ${totalValue} galleons.`);

Output ​

The total inventory value is 40 galleons.

Destructuring in Loops ​

Notice how we used destructuring in the loop:

javascript
for (const { price, quantity } of ingredients) {
  // Use price and quantity directly
}

This simplifies our code by extracting properties directly.

Contrasting Examples: Using for...in vs. for...of ​

Suppose we mistakenly use for...in on an array:

javascript
for (const index in ingredients) {
  console.log(ingredients[index]);
}

This works, but what if we try:

javascript
for (const ingredient in ingredients) {
  console.log(ingredient.name); // Undefined
}

Pitfall

Using for...in on arrays gives you indices (as strings), not the elements themselves. To access elements directly, use for...of.

Task: Updating Potion Quantities ​

Professor Snape asks you to update the quantities:

  • Increase Bezoar quantity by 3.
  • Decrease Unicorn Horn quantity by 1.

How can we efficiently update these quantities?

Task

  • Loop over the ingredients array.
  • Check if the ingredient name matches.
  • Update the quantity accordingly.
Reveal Solution
javascript
for (let ingredient of ingredients) {
  if (ingredient.name === "Bezoar") {
    ingredient.quantity += 3;
  } else if (ingredient.name === "Unicorn Horn") {
    ingredient.quantity -= 1;
  }
}

console.log(ingredients);

Output ​

javascript
[
  { name: "Bezoar", price: 10, quantity: 5 },
  { name: "Unicorn Horn", price: 20, quantity: 0 },
];

The Boundaries of Loops: When to Use Which Loop ​

How do you decide whether to use a for loop, for...in, or for...of?

  • for Loop: When you need full control over the iteration (indices, step size).
  • for...in Loop: When iterating over object properties (keys).
  • for...of Loop: When iterating over iterable objects (arrays, strings).

Contrasting Example: Iterating Over a String ​

Suppose we have a spell:

javascript
const spell = "Expecto Patronum";

How can we iterate over each character?

Using for...of:

javascript
for (const char of spell) {
  console.log(char);
}

Using for...in:

javascript
for (const index in spell) {
  console.log(spell[index]);
}

Both work, but which is more appropriate?

TIP

Use for...of when you want to iterate over the values directly in iterable objects like strings or arrays.

Task: Counting Characters in a Spell ​

Count how many times each character appears in the spell "Wingardium Leviosa".

Task

  • Initialize an empty object to keep counts.
  • Loop over each character in the spell.
  • Increment the count for each character.
  • Display the character counts.
Reveal Solution
javascript
const spell = "Wingardium Leviosa";
const charCounts = {};

for (const char of spell.replace(/\s+/g, "").toLowerCase()) {
  charCounts[char] = (charCounts[char] || 0) + 1;
}

console.log(charCounts);

Output ​

javascript
{
  w: 1, i: 3, n: 1, g: 1, a: 2,
  r: 1, d: 1, u: 1, m: 1, l: 1,
  e: 2, v: 1, o: 1, s: 1
}

Understanding Loop Boundaries with Arrays and Objects ​

What happens if we try to use a for...of loop on an object?

javascript
const potion = { name: "Polyjuice Potion", brewingTime: "1 month" };

for (const property of potion) {
  console.log(property);
}

Don'ts

This will result in a TypeError because objects are not iterable using for...of. Use for...in instead or iterate over Object.keys(potion).

Conclusion: Accio Mastery! ​

Congratulations! You've successfully navigated the enchanted world of JavaScript loops with the help of Hogwarts magic. You've learned:

  • The differences between for, for...in, and for...of loops.
  • How to iterate over arrays, objects, and strings.
  • When to use each type of loop to avoid common pitfalls.
  • How destructuring can simplify your code within loops.
  • The boundaries of loops and how improper use can lead to errors.

Remember, practice is key to mastering any spellβ€”or code! Keep exploring, experimenting, and soon you'll be a JavaScript wizard! πŸ§™β€β™‚οΈβœ¨

Additional Resources ​

Mischief Managed! ​

Thank you for joining this magical journey through JavaScript loops and objects. Keep coding, stay curious, and may your code be as bug-free as a well-brewed potion! ⚑