Episode 1 — Fundamentals / 1.23 — Objects

1.23 — JavaScript Objects: Quick Revision

Compact cheat sheet. Print-friendly.

How to use this material (instructions)

  1. Skim before labs or interviews.
  2. Drill gaps — reopen README.md1.23.a1.23.f.
  3. Practice1.23-Exercise-Questions.md and 1.23.g-Practice-Problems.md.
  4. Polish answers1.23-Interview-Questions.md.

Core vocabulary

TermOne-liner
ObjectCollection of key-value pairs (reference type)
PropertyA key-value pair on an object
MethodA property whose value is a function
KeyAlways a string or Symbol internally
ReferenceVariable holds a pointer to the object, not the object itself
Shallow copyNew top-level object; nested objects still shared
Deep copyFully independent clone at every level

Creating objects

// Object literal (most common)
const user = { name: "Alice", age: 25 };

// Empty object
const empty = {};

// Property shorthand
const name = "Alice";
const obj = { name };  // same as { name: name }

// Computed property name
const key = "email";
const obj2 = { [key]: "alice@example.com" };

Accessing properties

SyntaxWhen to use
obj.keyStatic, valid identifier keys (preferred)
obj["key"]Dynamic keys, special characters, variables
obj?.keySafe access (null/undefined short-circuits)
obj?.[key]Safe dynamic access
obj?.method()Safe method call
obj.name              // "Alice"
obj["full name"]      // bracket for spaces
obj[variable]         // bracket for dynamic keys
obj?.address?.city    // safe nested access
value ?? "default"    // nullish coalescing (null/undefined only)

?? vs ||

Value|| treats as falsy?? treats as nullish
nullYesYes
undefinedYesYes
0YesNo
""YesNo
falseYesNo

Adding, modifying, deleting

obj.newProp = value;            // add or modify
obj["new-prop"] = value;        // bracket add
delete obj.prop;                // remove entirely
obj.prop = undefined;           // clears value, key still exists!

delete vs = undefined

delete= undefined
"prop" in objfalsetrue
Object.keysNot listedListed

Property existence checks

"key" in obj                    // own + prototype chain
obj.hasOwnProperty("key")      // own only (legacy)
Object.hasOwn(obj, "key")      // own only (ES2022, preferred)

Copying objects

// Shallow copy
const shallow = { ...obj };
const shallow2 = Object.assign({}, obj);

// Deep copy (modern)
const deep = structuredClone(obj);

// Deep copy (legacy — loses Date, NaN, undefined, functions)
const legacy = JSON.parse(JSON.stringify(obj));

Shallow vs deep

Shallow: { ...obj }
  - Top-level: independent
  - Nested:    SHARED references

Deep: structuredClone(obj)
  - Top-level: independent
  - Nested:    independent

Non-mutating updates

// Spread with override
const updated = { ...obj, key: newValue };

// Immutable delete (destructure + rest)
const { removed, ...rest } = obj;

// Nested immutable update
const newState = {
  ...state,
  user: {
    ...state.user,
    address: { ...state.user.address, city: "Seattle" },
  },
};

Merging

// Spread (preferred, immutable)
const merged = { ...defaults, ...overrides };

// Object.assign (mutates target)
Object.assign(target, source1, source2);

// Non-mutating Object.assign
const merged2 = Object.assign({}, obj1, obj2);

Iterating objects

MethodReturnsIncludes prototype?
for...inKeys (one per loop)Yes
Object.keys(obj)string[]No
Object.values(obj)any[]No
Object.entries(obj)[string, any][]No
// Best pattern — entries + destructuring
for (const [key, value] of Object.entries(obj)) {
  console.log(key, value);
}

// Transform pipeline
const result = Object.fromEntries(
  Object.entries(obj)
    .filter(([key, val]) => typeof val === "number")
    .map(([key, val]) => [key, val * 2])
);

Property order rules

  1. Integer-like keys → sorted numerically ascending
  2. String keys → insertion order
  3. Symbol keys → insertion order (separate iteration)
Object.keys({ b: 1, a: 2, 2: "x", 1: "y" });
// ["1", "2", "b", "a"]

Methods and this

const obj = {
  name: "Alice",
  greet() {                      // method shorthand (preferred)
    return `Hi, ${this.name}`;   // this = calling object
  },
};

obj.greet();  // "Hi, Alice"

// AVOID arrow functions for methods:
const bad = {
  name: "Alice",
  greet: () => this.name,  // this is NOT the object!
};

Type checks

typeof {}               // "object"
typeof []               // "object" (array is an object)
typeof null             // "object" (historical bug)
typeof function(){}     // "function"

Array.isArray([])       // true
Array.isArray({})       // false

// Plain object check
value !== null && typeof value === "object" && !Array.isArray(value)

Object protection

MethodAdd?Delete?Modify?
Object.preventExtensionsNoYesYes
Object.sealNoNoYes
Object.freezeNoNoNo

All are shallow — nested objects are not affected.


Common patterns

// Pick specific keys
const pick = (obj, keys) =>
  Object.fromEntries(Object.entries(obj).filter(([k]) => keys.includes(k)));

// Omit specific keys
const omit = (obj, keys) =>
  Object.fromEntries(Object.entries(obj).filter(([k]) => !keys.includes(k)));

// Invert keys and values
const invert = (obj) =>
  Object.fromEntries(Object.entries(obj).map(([k, v]) => [v, k]));

// Check if empty
const isEmpty = (obj) => Object.keys(obj).length === 0;

// Group array by property
const groupBy = (arr, key) =>
  arr.reduce((acc, item) => {
    (acc[item[key]] ??= []).push(item);
    return acc;
  }, {});

Master workflow

  1. Create — object literal { key: value } with shorthand where applicable.
  2. Access — dot for static keys, bracket for dynamic, ?. for safety, ?? for defaults.
  3. Mutate — direct assignment; use spread for immutable updates.
  4. CheckObject.hasOwn(obj, key) for existence.
  5. IterateObject.entries(obj) + destructuring for key+value loops.
  6. Copy{ ...obj } for shallow, structuredClone(obj) for deep.
  7. Transformentries → map/filter → fromEntries pipeline.

End of 1.23 quick revision.