cf.completefrontendCode editorOpen lab
THE JAVASCRIPT FIELD GUIDE

Choosing a data structure

Choose between arrays, objects, Maps, Sets, and WeakMaps by comparing lookup, order, keys, duplicates, grouping, and performance trade-offs.

By the end you can choose confidently
  • 01
    Separate order from lookupDecide when a numbered list beats a keyed collection, and when it does not.
  • 02
    Pick the right key rulesExplain duplicates, string keys, object keys, and weak object keys.
  • 03
    Group and measure honestlyUse ES2024 grouping and reason about growth without fake timing claims.

Choose the bag for the job

JavaScript gives you several ways to hold data. Arrays, objects, Maps, Sets, and WeakMaps all store values, but they answer different questions. A structure is a promise to future readers: “this data is a list,” “this data is looked up by name,” or “duplicates do not belong here.”

This capstone pulls together Array basics and methods, Object basics, Map & Set, Set operations, WeakMap & WeakSet, and JSON. You do not need formal Big-O yet. We will say it plainly: how much extra work happens as your data grows?

The practical rule

Start with the question your code asks most often. “What is the next item?” points to an array. “Do we have this value?” points to a Set. “What value belongs to this key?” points to an object, Map, or WeakMap.

Real-life analogyPicking a structure is packing for a trip

You pack hiking boots in a backpack, not in a filing cabinet. Data is similar. The right container makes the common action easy and the rules obvious.

In real life: A suitcase with numbered outfits
In JavaScript: Array: ordered items, duplicates allowed
In real life: A phone book by name
In JavaScript: Object or Map: look up a value by key
In real life: A guest list at the door
In JavaScript: Set: membership and uniqueness
In real life: Sticky notes on borrowed gear
In JavaScript: WeakMap: metadata attached to objects you do not own

Where the analogy stops: Real bags can hold anything at once. Good programs usually choose one main promise per structure, then convert when a different view is needed.

We will compare lookup vs order, keys and duplicates, honest performance trade-offs, and ES2024 grouping with Object.groupBy and Map.groupBy.

Lookup vs order

STEP THROUGH

An array is a numbered line of people. It is excellent when position matters: first task, second task, last message, sorted score. But if you ask “is Ada in the line?” the array may need to check people one by one until it finds Ada.

A Set is a guest list. It cares about membership and uniqueness. A Map or object is a phone book: give it a key and it jumps to the value for that key. This is not magic; the engine builds lookup machinery because the collection’s job is key access.

Real-life analogyLine of people vs guest list

If you need the third person in line, a queue is perfect. If you only need to know whether someone is invited, the clipboard wins.

In real life: A numbered queue
In JavaScript: Array index and order
In real life: Walking down the queue looking for a name
In JavaScript: array.includes(value)
In real life: Checking a clipboard at the door
In JavaScript: set.has(value)

Where the analogy stops: JavaScript engines optimize arrays heavily, and tiny lists are often fine. The analogy is about the growth pattern, not exact timing.

Array line or Set guest list?
Step 0 of 6Ready
Your turn: follow the blue line

Step through a duplicate-friendly array and a uniqueness-focused Set answering the same lookup question.

Running in
  1. script
Next: line 1
Click the blue line to take the next stepPop out in the code editor (opens in a new tab)JavaScript
const blockedSet = new Set(blockedNames);const name = "bot";const arrayAnswer = blockedNames.includes(name);const setAnswer = blockedSet.has(name);console.log(arrayAnswer, setAnswer);
CallStoreChangeResultRun = next line. Ran = already executed.
Recent returnsNothing yet. Start with the blue line.
A guided replay recorded from real JavaScript calls, not an engine debugger. Step follows executed statements; Back reviews a snapshot. Reset starts a fresh run.

Notice that both checks return the same answer. The structure choice is about the rule you mean and the work your program repeats.

Keys & duplicates

STEP THROUGH

Duplicates are not automatically bad. A shopping cart can contain two identical mugs. A search history can include the same query twice. Arrays allow that because each entry has its own position. Sets do not: a value is either present or absent.

Keys have rules too. Ordinary object property keys are strings or Symbols. That makes objects perfect for JSON-shaped records such as { theme: "dark" }, but it means the number 1 and the string "1" collide. Map keeps key types and object identity.

Watch object keys collide and Map keys stay separate
Step 0 of 9Ready
Your turn: follow the blue line

Watch ordinary object keys become strings while Map keys keep their original identity.

Running in
  1. script
Next: line 1
Click the blue line to take the next stepPop out in the code editor (opens in a new tab)JavaScript
const plain = {};plain[1] = "number one";plain["1"] = "string one";const typed = new Map();typed.set(1, "number one");typed.set("1", "string one");typed.set(objectKey, "object key");console.log(plain[1], typed.size, typed.get(objectKey));
CallStoreChangeResultRun = next line. Ran = already executed.
Recent returnsNothing yet. Start with the blue line.
A guided replay recorded from real JavaScript calls, not an engine debugger. Step follows executed statements; Back reviews a snapshot. Reset starts a fresh run.
Choosing by shape and key rules
StructureBest forOrdered?Duplicates?Key typesLookupIterateJSON-friendly
ArrayOrdered lists, queues, sorted resultsYes, by indexYesIndex numbersSearch methods scan unless indexed separatelyExcellentYes
ObjectSimple records and string-key dictionariesProperty order has rules; not the main featureOne value per keyString and Symbol property keysFast property access by keyObject.keys / entriesYes
MapFrequently changing dictionaries and non-string keysYes, insertion orderOne value per keyAny value, including objectsFast key lookupExcellentNeeds conversion
SetUnique values and membership testsYes, insertion orderNoValues are the keysFast membership lookupExcellentNeeds conversion
WeakMapPrivate metadata or caches for objectsNoOne value per object keyObjects and non-registered SymbolsFast by object identityNo iterationNo
JSON reminder

JSON stores arrays, objects, strings, numbers, booleans, and null. It does not directly store Map, Set, or WeakMap. Convert them to arrays or plain objects before sending or saving.

Performance trade-offs

INTERACTIVE

Performance starts with growth, not folklore. If a loop calls blocked.includes(user) for every user, the program may scan the blocked list again and again. Turning the blocked list into a Set once lets each membership check ask blockedSet.has(user).

People often write this as O(n) versus O(1): array search work usually grows with the number of items, while Set membership is designed to stay roughly direct. That notation is useful later. For now, read it as “walking the line” versus “checking the clipboard.”

Measure includes vs has honestly
Lookup benchmark sourcePop out in the code editor (opens in a new tab)JavaScript
const items = Array.from({ length: 1000 }, (_, i) => "item-" + i);const set = new Set(items);items.includes("item-999"); // may scan many itemsset.has("item-999");       // asks the Set lookup table
Measured here

No numbers yet. Press Run benchmark to measure in your browser.

The growth idea matters more than the exact number: an array lookup usually checks values one by one, while a Set lookup is designed to jump straight to a membership answer.

Try it yourself

Choose a size, then run it on this device.

Timings vary by browser, device, battery, and current load. Use them as a local observation, not a universal promise.

Be honest with benchmarks. Timings vary by machine, browser engine, power mode, and surrounding work. The playground runs in your browser only after you click, repeats short runs, and reports a median “on this device.” Tests should prove correctness, not speed.

Object.groupBy & Map.groupBy

STEP THROUGH

Grouping turns one ordered list into buckets. ES2024 adds Object.groupBy(items, callback) and Map.groupBy(items, callback). Use Object.groupBy when the group keys are property keys such as strings or Symbols. Use Map.groupBy when keys are objects or other non-string values.

Feature detection in your browser: Checking this browser after the page mounts…

Group products by category
Step 0 of 5Ready
Your turn: follow the blue line

Group an array with ES2024 Object.groupBy and inspect the clean dictionary it returns.

Running in
  1. script
Next: line 1
Click the blue line to take the next stepPop out in the code editor (opens in a new tab)JavaScript
  { name: "Notebook", category: "stationery" },  { name: "Pen", category: "stationery" },  { name: "Tea", category: "pantry" },];const byCategory = Object.groupBy(products, item => item.category);const prototype = Object.getPrototypeOf(byCategory);console.log(byCategory.stationery.map(item => item.name).join(", "));console.log(prototype === null);
CallStoreChangeResultRun = next line. Ran = already executed.
Recent returnsNothing yet. Start with the blue line.
A guided replay recorded from real JavaScript calls, not an engine debugger. Step follows executed statements; Back reviews a snapshot. Reset starts a fresh run.
Map.groupBy when the key is an objectPop out in the code editor (opens in a new tab)JavaScript
const kitchen = { team: "kitchen" };const office = { team: "office" };const products = [  { name: "Tea", owner: kitchen },  { name: "Notebook", owner: office },];const byOwner = Map.groupBy(products, item => item.owner);console.log(byOwner.get(kitchen).map(item => item.name));

Object.groupBy returns a null-prototype object. That is a clean dictionary, but it also means methods from Object.prototype are not sitting on the result. Use Object.hasOwn(result, key) rather than result.hasOwnProperty(key).

Decision guide

INTERACTIVE

You rarely choose from memory. Ask a few questions: does order matter? Do I look up by key? Are duplicates allowed? Are the keys objects? Should object-keyed metadata disappear when the object can be garbage collected? Do I need JSON?

Decision helper: choose a structure
Decision inputsPop out in the code editor (opens in a new tab)JavaScript
recommendStructure({  ordered: true,  keyed: false,  duplicates: true,  objectKeys: false,  weakLifetime: false,  json: false,});
Recommendation
StructureArray
ReasonArrays are the default for ordered lists that can contain duplicates.
Starter snippetPop out in the code editor (opens in a new tab)JavaScript
const tasks = ["plan", "build", "ship"];
Try it yourself

Recommended: Array. Arrays are the default for ordered lists that can contain duplicates.

This helper is deterministic, not magical. It turns the lesson’s rules into a first guess you can revise.
Which structure fits?
  • Track unique visitor IDs for this page view
  • Render a to-do list in the order the user arranged it
  • Read settings such as theme and language by name and save as JSON
  • Cache measurements per DOM node without keeping old nodes alive
  • Group orders by status strings like paid and shipped
  • Process tasks first-in, first-out
  • Count how often each word appears
  • Keep a unique list of tags while preserving first-seen order
Try it yourself
0 of 8 correct

Sort each real scenario by the structure you would reach for first. Some production systems combine structures, but each card has one best first choice.

Choose a category for every card. You can change an answer at any time; Reset clears them all.

Where you’ll use this

These choices show up in ordinary app code:

Practical patternsPop out in the code editor (opens in a new tab)JavaScript
// 1. Ordered UI stateconst tasks = ["write", "review", "ship"]; // 2. JSON-friendly settingsconst settings = { theme: "dark", density: "compact" }; // 3. Counting with a Mapconst counts = new Map();counts.set("bug", (counts.get("bug") ?? 0) + 1); // 4. Fast membership with a Setconst selectedIds = new Set([101, 104, 108]); // 5. Metadata for objects you do not ownconst measurements = new WeakMap();

It is normal to convert: receive JSON as objects and arrays, build a Map for repeated lookups, then convert back before saving. The structure nearest the boundary does not have to be the structure in the middle of your algorithm.

Common misconceptions

“Map is always better than object.”

Objects are still ideal for fixed records and JSON. Map shines for dynamic dictionaries, object keys, and frequent entry changes.

“Set sorts or magically cleans data.”

Set removes duplicates using SameValueZero equality and preserves first-seen insertion order. It does not sort values.

“WeakMap is just a faster Map.”

WeakMap is about lifetime. It only accepts object-like keys and cannot be iterated, because entries may disappear when keys are no longer reachable.

“Objects remember every key exactly as written.”

Ordinary object keys become strings unless they are Symbols. Use a Map when number keys, object keys, or separate key types matter.

“Benchmarks tell the whole truth.”

Small timing tests are clues, not laws. First choose the structure that expresses the job; measure real bottlenecks in real code.

Practice: choose and transform

5 EXERCISES
Exercise 1 · Warm-upPick a cart structure

A shopping cart must show items in the order added, and duplicate items are allowed. Which structure fits best?

Starter codePop out in the code editor (opens in a new tab)JavaScript
// Best structure for a shopping cart shown in item order, duplicates allowed:
console.log("Array");

Answer, then press Check. Spacing and letter case don’t matter.

    Exercise 2 · PracticeRefactor includes in a loop

    Read the refactored code. It should keep every user not in the blocked list, including duplicate allowed users.

    Starter codePop out in the code editor (opens in a new tab)JavaScript
    const users = ["Ada", "Lin", "Grace", "Ada"];
    const blocked = ["Lin"];
    const blockedSet = new Set(blocked);
    console.log(users.filter(user => !blockedSet.has(user)).join(","));

    Answer, then press Check. Spacing and letter case don’t matter.

      Exercise 3 · PracticeGroup orders by status

      Use Object.groupBy for string status groups. What paid IDs print?

      Starter codePop out in the code editor (opens in a new tab)JavaScript
      const orders = [
        { id: 1, status: "paid" },
        { id: 2, status: "new" },
        { id: 3, status: "paid" },
      ];
      const byStatus = Object.groupBy(orders, order => order.status);
      console.log(byStatus.paid.map(order => order.id).join(","));

      Answer, then press Check. Spacing and letter case don’t matter.

        Exercise 4 · PracticeCount with a Map

        Trace the loop. What count is stored for the word map?

        Starter codePop out in the code editor (opens in a new tab)JavaScript
        const words = ["map", "set", "map"];
        const counts = new Map();
        for (const word of words) {
          counts.set(word, (counts.get(word) ?? 0) + 1);
        }
        console.log(counts.get("map"));

        Answer, then press Check. Spacing and letter case don’t matter.

          Exercise 5 · ChallengeDedupe while keeping order

          What unique tag order prints after turning an array into a Set and back?

          Starter codePop out in the code editor (opens in a new tab)JavaScript
          const tags = ["js", "css", "js", "html", "css"];
          console.log([...new Set(tags)].join(","));

          Answer, then press Check. Spacing and letter case don’t matter.

            Quiz: check your understanding

            7 QUESTIONS
            Lesson quiz · 7 questionsScore: first tries count
            1. Question 1 of 7You need to display messages exactly in arrival order, including duplicates. What should you start with?

              Choose an answer to see the explanation.

            2. Question 2 of 7What does this Set size code print?

              Read the code, then predictPop out in the code editor (opens in a new tab)JavaScript
              const ids = [1, 1, 2];
              console.log(new Set(ids).size);

              Choose an answer to see the explanation.

            3. Question 3 of 7What does this object key collision print?

              Read the code, then predictPop out in the code editor (opens in a new tab)JavaScript
              const data = {};
              data[1] = "number";
              data["1"] = "string";
              console.log(data[1]);

              Choose an answer to see the explanation.

            4. Question 4 of 7Which collection keeps object keys by identity and lets you iterate all entries?

              Choose an answer to see the explanation.

            5. Question 5 of 7What does this grouping code print?

              Read the code, then predictPop out in the code editor (opens in a new tab)JavaScript
              const products = [
                { type: "book", name: "JS" },
                { type: "tool", name: "Pen" },
                { type: "book", name: "CSS" },
              ];
              const grouped = Object.groupBy(products, item => item.type);
              console.log(grouped.book.length);

              Choose an answer to see the explanation.

            6. Question 6 of 7When is a timing playground honest?

              Choose an answer to see the explanation.

            7. Question 7 of 7What does this Map key code print?

              Read the code, then predictPop out in the code editor (opens in a new tab)JavaScript
              const map = new Map();
              map.set(1, "number");
              map.set("1", "string");
              console.log(map.size);

              Choose an answer to see the explanation.

            Key takeaways

            • Arrays are ordered lists. Reach for them when position, sorting, or duplicates matter.
            • Objects are JSON-friendly records and simple string-key dictionaries.
            • Maps keep key identity and type; Sets keep unique values and fast membership checks.
            • WeakMaps attach values to object keys without keeping those keys alive and without iteration.
            • Use Object.groupBy for property-key groups and Map.groupBy for object or non-string keys.

            Remember the one-liner.
            Choose the structure whose rules match your most common question: order, key lookup, uniqueness, or object lifetime.

            Up next: Date & time.

            CompleteFrontend Clear concepts. Working examples.