webdev.complete
📦 Data: Arrays, Objects, Maps
JavaScript
Lesson 30 of 117
25 min

Objects, Maps & Sets

When to reach for Map vs object, destructuring, spread.

If arrays are JS's lists, objects are its everything else: bags of named values, lookup tables, config blobs, models, options arguments. There's also Map and Set, which are objects' cousins for specific jobs. Let's learn when to use which.

Object literals

js
const user = {
  name: "Ada",
  age: 36,
  role: "admin",
};

user.name        // "Ada"
user["name"]     // "Ada"
user.age = 37;   // properties can change

// Add new keys
user.email = "ada@example.com";

// Remove a key
delete user.age;

Shorthand and computed keys

js
const name = "Ada";
const age = 36;

// Shorthand: { name, age } means { name: name, age: age }
const user = { name, age };

// Computed keys (any expression in [brackets])
const field = "role";
const u = {
  [field]: "admin",
  [`is_${field}`]: true,
};
// { role: "admin", is_role: true }

// Method shorthand
const obj = {
  greet() { return "hi"; },       // same as greet: function () { ... }
};

Object.keys / values / entries

js
const user = { name: "Ada", age: 36, role: "admin" };

Object.keys(user);    // ["name", "age", "role"]
Object.values(user);  // ["Ada", 36, "admin"]
Object.entries(user); // [["name","Ada"], ["age",36], ["role","admin"]]

// Loop nicely
for (const [key, value] of Object.entries(user)) {
  console.log(key, "=", value);
}

// Build an object back from entries
Object.fromEntries([["a", 1], ["b", 2]]);  // { a: 1, b: 2 }

Destructuring objects

js
const user = { name: "Ada", age: 36, role: "admin" };

// Pull out values
const { name, role } = user;

// Defaults
const { city = "Unknown" } = user;   // city = "Unknown"

// Rename while destructuring
const { name: userName } = user;     // userName = "Ada"

// Rest collects the rest
const { name: n, ...other } = user;
// n = "Ada", other = { age: 36, role: "admin" }

// Combine: nested destructuring with rename and default
const settings = { theme: { color: "dark" } };
const { theme: { color: themeColor = "light" } } = settings;
Destructuring in parameters
You can destructure right in a function signature. This is how modern JS handles "options" objects:
js
function greet({ name = "stranger", greeting = "Hello" } = {}) {
  return `${greeting}, ${name}!`;
}

greet();                          // "Hello, stranger!"
greet({ name: "Ada" });           // "Hello, Ada!"

Map: when an object isn't the right tool

Objects work as lookup tables, but they have baggage: keys are always strings or symbols, they have inherited properties, and iteration order can be weird. Map fixes all three:

js
const cache = new Map();

cache.set("a", 1);
cache.set("b", 2);
cache.get("a");        // 1
cache.has("a");        // true
cache.delete("a");
cache.size;            // 1

// Keys can be any value - objects, functions, anything
const key = { id: 1 };
cache.set(key, "user data");
cache.get(key);        // "user data"

// Iteration order is insertion order, always
for (const [k, v] of cache) {
  console.log(k, v);
}
Object vs Map
Reach for Mapwhen keys aren't strings, when you add and remove keys often, or when you need to know the size. Reach for an object literal for fixed-shape records and config.

Set: unique values

js
const tags = new Set(["a", "b", "a", "c", "b"]);
tags.size;             // 3 - duplicates dropped

tags.has("a");         // true
tags.add("d");
tags.delete("a");

// Dedupe an array in one line
const unique = [...new Set([1, 2, 2, 3, 3, 3, 4])];
// [1, 2, 3, 4]

// ES2025 set methods
const a = new Set([1, 2, 3]);
const b = new Set([2, 3, 4]);

a.union(b);          // Set {1, 2, 3, 4}
a.intersection(b);   // Set {2, 3}
a.difference(b);     // Set {1}

Copying objects: shallow vs deep

js
const original = { name: "Ada", address: { city: "London" } };

// Shallow copy: top level is new, nested objects are shared
const shallow1 = { ...original };
const shallow2 = Object.assign({}, original);

shallow1.address.city = "Paris";
original.address.city;  // "Paris" - they share the nested object!

// Deep copy with structuredClone (built-in, recursive)
const deep = structuredClone(original);
deep.address.city = "Berlin";
original.address.city;  // unchanged
structuredClone is the modern answer
structuredClone handles dates, maps, sets, typed arrays, even cyclic references. It cannot clone functions, DOM nodes, or class instances (those become plain objects).

Equality: objects compare by reference

js
{} === {}              // false - different objects
[] === []              // false

const a = { x: 1 };
const b = a;
a === b;               // true - same reference

For value equality, compare fields manually or use a library. For cache keys, this is exactly why Map exists.

Try the patterns

// Build a small "users" lookup
const users = {
  ada:   { name: "Ada Lovelace",      role: "founder" },
  grace: { name: "Grace Hopper",      role: "admiral" },
  marg:  { name: "Margaret Hamilton", role: "engineer" },
};

// Destructure with rename + default
const { ada: { name: adaName, age = "unknown" } } = users;
console.log(adaName, age);

// entries -> transform -> back to object
const upperRoles = Object.fromEntries(
  Object.entries(users).map(([k, u]) => [k, { ...u, role: u.role.toUpperCase() }])
);
console.log(upperRoles);

// Deep clone vs spread
const original = { a: 1, nested: { b: 2 } };
const shallow = { ...original };
const deep = structuredClone(original);

shallow.nested.b = 99;
console.log("original.nested.b:", original.nested.b); // 99 - shared!
console.log("deep.nested.b:",     deep.nested.b);     // 2  - independent

// Dedupe
const dupes = ["a", "b", "a", "c", "b", "a"];
console.log("unique:", [...new Set(dupes)]);

// Use a Map with non-string keys
const meta = new Map();
const userObj = { id: 1 };
meta.set(userObj, { lastSeen: Date.now() });
console.log(meta.get(userObj));

Quiz

Quiz1 / 4

What does Object.entries({ a: 1, b: 2 }) return?

Recap

  • Object literals: shorthand, computed keys, method shorthand are all standard.
  • Object.keys/values/entries + destructuring is how you work with object data.
  • Use Map for arbitrary keys and known size. Use Set for uniqueness.
  • Spread is a shallow copy. structuredClone is a true deep copy.
  • Objects compare by reference, never by content.
Built with Next.js, Tailwind & Sandpack.
Learn. Build. Ship.