All exercises use the tea shop data. Start by loading it:
import { teas } from "../../data/teas.js";forEach walks through each item. No return value - just side effects.
📚 Recall: Side Effect
A side effect is when a function modifies something outside itself - like logging to console or updating a variable. forEach is designed for side effects.
Log each tea's name to the console.
Log each tea in the format: "Sencha (Japan)"
Count how many teas are organic. Use a variable outside the forEach to track the count.
💡 Notice: You're modifying an external variable (
count). That's a side effect - and exactly whatforEachis for.
map transforms each item. Same count in, same count out.
💡 Unlike
forEach,maphas no side effects. It creates a new array without changing the original.
Create an array containing just the tea names.
// Expected: ["Sencha", "Earl Grey", "Dragon Well", ...]Create an array of prices in DKK for 100 grams (multiply pricePerGram by 100).
// Expected: [12, 8, 25, ...]Create an array of display strings in the format: "Sencha - 12 DKK/100g"
filter keeps items that match. Fewer items out, same shape.
📚 Recall: Predicate
The function you pass to filter is called a predicate - a function that returns true or false. Items where the predicate returns true are kept.
Get all organic teas.
Get all teas from Japan.
Get all teas with caffeineLevel equal to "high".
Get all teas that are both in stock AND organic.
💡 The items themselves aren't changed - they're just selected. That's the difference between
filter(select) andmap(transform).
Chain methods together: the output of one becomes input to the next.
📚 Recall: Pipeline
When you chain methods, data flows through like water through pipes. Each step's output becomes the next step's input. This is a pipeline.
Get the names of all green teas.
// filter to green type, then map to namesGet display prices (format: "Sencha - 12 DKK/100g") for organic teas only.
Get Japanese teas sorted by price (lowest first).
// Hint: .sort((a, b) => a.pricePerGram - b.pricePerGram)Rewrite the exercises above using arrow function syntax.
Rewrite exercises 1-3 using arrow functions.
Rewrite exercises 4-6 using arrow functions with implicit return (no curly braces).
Example:
// Traditional
teas.map(function (tea) {
return tea.name;
});
// Arrow with implicit return
teas.map((tea) => tea.name);When do you need explicit return (curly braces)?
Rewrite exercise 6 both ways:
- With implicit return (hint: use template literals inline)
- With explicit return (curly braces and
returnkeyword)
Build a filterTeas(teas, criteria) function that accepts a filter object:
filterTeas(teas, { organic: true });
// Returns all organic teas
filterTeas(teas, { origin: "Japan" });
// Returns all Japanese teas
filterTeas(teas, { organic: true, origin: "Japan" });
// Returns organic Japanese teas
filterTeas(teas, { type: "green", inStock: true });
// Returns green teas that are in stockThe function should work with any combination of filter properties.
📚 This is declarative programming
Instead of writing specific filter functions for each case, you're describing what you want with a data structure (the criteria object). The function figures out how to apply it. That's declarative.