Kazi Rahamatullah
Kazi Rahamatullah
AboutProjectsBlogContact
UsesBooks
ResumeView CV
Kazi Rahamatullah

© Copyright 2026 Kazi Rahamatullah

AboutProjectsBlogBooksUses
Twitter/XGitHubProduct HuntCodeSandbox
Back to Blog
JavaScriptObjectsInterview PreparationFrontend DevelopmentES6

JavaScript Objects

Master JavaScript objects for interviews — literals, destructuring, cloning, Map/Set, descriptors, utility patterns, and practice problems with solutions.

Jul 3, 202627 min read

Introduction

Objects are the backbone of JavaScript — configuration, API payloads, React props, and normalized state all live here. This guide walks through fundamentals, senior-level patterns, and practice problems with detailed solutions.

Course Reference

Quick index

#Section
1Creation & literals
2Property access & optional chaining
3Object.keys, values, entries
4Spread & Object.assign
5Object destructuring
6Shallow vs deep copy
7Object.is, hasOwn, in
8Descriptors, freeze, seal
9Object.create & prototypes
10Map & Set
11Utility patterns

1. Creation & literals

Object literal

javascript
const user = {
  id: 'u1',
  name: 'Alice',
  role: 'admin',
  'full name': 'Alice Smith', // quoted key when needed
  isActive: true,
}

new Object() constructor

javascript
const user = new Object()
user.id = 'u1'
user.name = 'Alice'
 
// Prefer literals — shorter and idiomatic
const better = { id: 'u1', name: 'Alice' }

Computed property names

javascript
const field = 'status'
const record = { [field]: 'active' } // { status: 'active' }
 
const key = 'userId'
const dynamic = {
  [key]: 42,
  [`${key}_label`]: 'User ID',
}

Method shorthand

javascript
const cart = {
  items: {},
  add(id) {
    this.items[id] = (this.items[id] ?? 0) + 1
  },
  total() {
    return Object.values(this.items).reduce((sum, qty) => sum + qty, 0)
  },
}

Interview Answer

Use object literals {} for plain data records and configuration. Use computed keys [expression] when property names are dynamic (API fields, form names).

Back to index


2. Property access & optional chaining

Dot vs bracket notation

javascript
const user = { name: 'Alice', role: 'admin' }
 
user.name // 'Alice' — dot for known keys
user['role'] // 'admin' — bracket for dynamic keys
 
const key = 'name'
user[key] // 'Alice'

Add, update, delete

javascript
const product = { id: 1, name: 'Mug' }
 
product.price = 12.99 // add / update
product['inStock'] = true
 
delete product.inStock // removes own property

Optional chaining (?.)

javascript
const user = { profile: { city: 'NYC' } }
 
user.profile?.city // 'NYC'
user.address?.city // undefined — no error
user.address?.city ?? 'Remote' // 'Remote'
user.getName?.() // safe method call

Nullish coalescing (??)

javascript
const settings = { theme: null, fontSize: 0 }
 
settings.theme ?? 'light' // 'light' — null/undefined only
settings.fontSize ?? 14 // 0 — 0 is valid, not replaced

Interview trap:

javascript
const obj = { a: undefined }
obj.a ?? 'default' // 'default'
'a' in obj // true — key exists even if value is undefined!

Back to index


3. Object.keys, values, entries

javascript
const scores = { alice: 90, bob: 75, carol: 88 }
 
Object.keys(scores) // ['alice', 'bob', 'carol']
Object.values(scores) // [90, 75, 88]
Object.entries(scores) // [['alice', 90], ['bob', 75], ['carol', 88]]

Object.fromEntries

javascript
const pairs = [
  ['x', 1],
  ['y', 2],
]
Object.fromEntries(pairs) // { x: 1, y: 2 }
 
// Transform object immutably
const curved = Object.fromEntries(Object.entries(scores).map(([name, score]) => [name, score + 5]))

Iterate objects

javascript
// Preferred — own enumerable string keys
for (const [name, score] of Object.entries(scores)) {
  console.log(name, score)
}
 
// for...in — includes inherited enumerable keys (usually avoid)
for (const key in scores) {
  if (Object.hasOwn(scores, key)) {
    console.log(key, scores[key])
  }
}

Interview Answer

Object.keys/values/entries only return own enumerable properties. Use Object.entries + map/filter + fromEntries to transform objects without mutation.

Back to index


4. Spread & Object.assign

Merge objects

javascript
const defaults = { theme: 'light', pageSize: 10 }
const userPrefs = { pageSize: 25, lang: 'en' }
 
const merged = { ...defaults, ...userPrefs }
// { theme: 'light', pageSize: 25, lang: 'en' } — later keys win

Object.assign

javascript
const target = {}
Object.assign(target, defaults, userPrefs)
// mutates target, returns target

Immutable single-field update

javascript
const user = { id: 1, name: 'Alice', role: 'viewer' }
 
const promoted = { ...user, role: 'admin' }
 
// Nested update (Redux-style)
const state = { cart: { p1: { qty: 1 } }, user: { name: 'Alice' } }
const next = {
  ...state,
  cart: {
    ...state.cart,
    p1: { ...state.cart.p1, qty: 2 },
  },
}

Interview Answer

Spread creates a shallow copy. Later spread arguments overwrite earlier keys. Object.assign mutates its first argument; spread does not mutate the source.

Back to index


5. Object destructuring

Basic, rename, default

javascript
const employee = {
  id: 'e1',
  name: 'Alice',
  department: 'Eng',
  salary: 90000,
}
 
const { name, department } = employee
const { name: employeeName } = employee
const { role = 'viewer' } = employee // default when missing

Rest — omit pattern

javascript
const { id, ...rest } = employee
// rest = { name, department, salary } — id omitted

Nested destructuring

javascript
const data = { user: { profile: { city: 'NYC', zip: '10001' } } }
 
const {
  user: {
    profile: { city },
  },
} = data

Function parameters

javascript
function renderRow({ name, salary, status = 'active' }) {
  return `${name} (${status}): $${salary}`
}
 
renderRow({ name: 'Alice', salary: 90000 })

Swap object properties

javascript
let a = { x: 1 }
let b = { x: 2 }
;[a, b] = [b, a]

Interview Answer

Destructuring extracts shape cleanly from API responses, React props, and config. Rest (...rest) collects remaining keys — ideal for omitting password before sending to client.

Back to index


6. Shallow vs deep copy

javascript
const original = { a: 1, nested: { b: 2 }, tags: ['js'] }
 
// Shallow — top-level new reference, nested shared
const shallow = { ...original }
shallow.nested.b = 99
original.nested.b // 99 — mutated!
 
// Deep — modern built-in
const deep = structuredClone(original)
deep.nested.b = 0
original.nested.b // 99 — unchanged
 
// JSON trick — loses Date, Map, undefined, functions, Symbol
const jsonCopy = JSON.parse(JSON.stringify(original))
MethodDepthHandles Date / Map / functions
spread / Object.assignShallowN/A
structuredCloneDeepYes (most built-in types)
JSON.parse/stringifyDeepNo

Interview Answer

In React/Redux, always return new object references at the level you change. Shallow spread is enough for flat updates; use structuredClone or Immer for deep trees.

Back to index


7. Object.is, hasOwn, in

Object.is — SameValue equality

javascript
Object.is(NaN, NaN) // true  (NaN === NaN is false)
Object.is(-0, +0) // false (=== treats them as equal)

in vs Object.hasOwn

javascript
const user = { name: 'Alice' }
 
'name' in user // true
'toString' in user // true — inherited from prototype!
Object.hasOwn(user, 'name') // true — own property only
Object.hasOwn(user, 'toString') // false

Legacy hasOwnProperty

javascript
user.hasOwnProperty('name') // true — can be overridden on object
// Prefer Object.hasOwn (ES2022)

Interview Answer

Use Object.hasOwn(obj, key) to check own properties. Use in when inherited properties matter. Object.is is for edge cases like NaN and -0.

Back to index


8. Descriptors, freeze, seal

Object.defineProperty

javascript
const user = {}
Object.defineProperty(user, 'id', {
  value: 1,
  writable: false,
  enumerable: true,
  configurable: false,
})
 
user.id = 2 // fails silently (strict mode: TypeError)

freeze, seal, preventExtensions

javascript
const obj = { name: 'Alice', meta: { age: 30 } }
 
Object.freeze(obj) // no add / delete / change own props (shallow)
Object.seal(obj) // can change values, not add/delete keys
Object.preventExtensions(obj) // no new keys, can delete/change existing
 
obj.meta.age = 31 // still works after freeze — nested not frozen!

Interview Answer

Object.freeze is shallow. Nested objects remain mutable. For immutable app state, use Immer or immutable update patterns — not freeze alone in production.

Back to index


9. Object.create & prototypes

Create with explicit prototype

javascript
const animal = {
  speak() {
    return `${this.name} speaks`
  },
}
 
const dog = Object.create(animal)
dog.name = 'Rex'
dog.speak() // 'Rex speaks'

Clone with property descriptors

javascript
const src = {
  get label() {
    return 'src'
  },
}
const clone = Object.create(Object.getPrototypeOf(src), Object.getOwnPropertyDescriptors(src))

Interview Answer

Object.create(proto) sets the prototype chain without a constructor — useful for delegation patterns. For data cloning in apps, prefer spread or structuredClone.

Back to index


10. Map & Set

Map — any key type, insertion order

javascript
const cache = new Map()
 
cache.set('user:1', { name: 'Alice' })
cache.set(42, 'answer')
cache.set({ id: 1 }, 'metadata')
 
cache.get('user:1') // { name: 'Alice' }
cache.has(42) // true
cache.size // 3
cache.delete(42)
 
for (const [key, value] of cache) {
  console.log(key, value)
}

Object → Map → Object

javascript
const obj = { a: 1, b: 2 }
const map = new Map(Object.entries(obj))
const back = Object.fromEntries(map)

Set — unique values

javascript
const ids = [1, 2, 2, 3, 3, 3]
const unique = [...new Set(ids)] // [1, 2, 3]
ObjectMapSet
Keysstring / symbolanyunique values
Sizemanual count.size.size
Defaulthas prototypecleanclean
JSONserializablenot directlynot directly

Interview Answer

Use Object for JSON-like records and configs. Use Map when keys are not strings or you add/delete frequently. Use Set for uniqueness (dedupe ids, tags).

Back to index


11. Utility patterns

Pick & omit

javascript
function pick(obj, keys) {
  return Object.fromEntries(keys.filter((k) => k in obj).map((k) => [k, obj[k]]))
}
 
function omit(obj, keys) {
  const exclude = new Set(keys)
  return Object.fromEntries(Object.entries(obj).filter(([k]) => !exclude.has(k)))
}
 
const user = { id: 1, name: 'Alice', password: 'secret' }
pick(user, ['id', 'name']) // safe public fields
omit(user, ['password']) // strip sensitive fields

Shallow equal

javascript
function shallowEqual(a, b) {
  if (Object.is(a, b)) return true
  if (!a || !b || typeof a !== 'object' || typeof b !== 'object') return false
 
  const keysA = Object.keys(a)
  const keysB = Object.keys(b)
  if (keysA.length !== keysB.length) return false
 
  return keysA.every((key) => Object.is(a[key], b[key]))
}

Normalize array → object by id

javascript
const products = [
  { id: 'p1', name: 'Mug' },
  { id: 'p2', name: 'Book' },
]
 
const byId = Object.fromEntries(products.map((p) => [p.id, p]))
// { p1: { id: 'p1', name: 'Mug' }, p2: { ... } }
 
// Or with reduce
const byId2 = products.reduce((acc, p) => {
  acc[p.id] = p
  return acc
}, {})

Object.groupBy (ES2024)

javascript
const employees = [
  { name: 'A', dept: 'Eng' },
  { name: 'B', dept: 'Sales' },
  { name: 'C', dept: 'Eng' },
]
 
const byDept = Object.groupBy(employees, (e) => e.dept)
// { Eng: [...], Sales: [...] }

Deep merge (one level vs recursive)

javascript
function deepMerge(target, source) {
  const out = { ...target }
  for (const [key, value] of Object.entries(source)) {
    if (value && typeof value === 'object' && !Array.isArray(value) && target[key] && typeof target[key] === 'object') {
      out[key] = deepMerge(target[key], value)
    } else {
      out[key] = value
    }
  }
  return out
}

Back to index


Quick reference

TaskAPI
List keysObject.keys
List valuesObject.values
Key-value pairsObject.entries
Pairs → objectObject.fromEntries
Mergespread, Object.assign
Clone shallow{ ...obj }
Clone deepstructuredClone
Own property checkObject.hasOwn
Freeze (shallow)Object.freeze
Dynamic key{ [key]: value }
Safe nested access?. optional chaining
Same-value checkObject.is
Create with prototypeObject.create
Unique valuesSet
Any-type keysMap

Practice Problems

Quick index

1. Fundamentals (T-001 – T-020)

#Question
T-001: Create a user object using an object literal
T-002: Create an object using new Object()
T-003: Access property with dot and bracket notation
T-004: Add and update properties
T-005: Delete a property with delete
T-006: Check property with in vs Object.hasOwn
T-007: Destructure name and email
T-008: Destructure with rename and default
T-009: Rest destructuring to omit password
T-010: Nested destructuring
T-011: Shallow clone with spread
T-012: Deep clone with structuredClone
T-013: Merge configs with spread
T-014: Object.assign vs spread
T-015: Object.keys, values, entries
T-016: Object.fromEntries
T-017: Loop with Object.entries and for...of
T-018: freeze vs seal vs preventExtensions
T-019: Read-only property with defineProperty
T-020: Optional chaining and nullish coalescing

2. Product dataset (T-021 – T-040)

#Question
T-021: Filter products in "Stationery" category
T-022: Format as "Mug (Kitchen)"
T-023: Find highest-priced product
T-024: Any product out of stock?
T-025: Function filterByMinPrice
T-026: Extract product names only
T-027: Total value of in-stock products
T-028: Any product priced below 5?
T-029: Find product with price exactly 8.5
T-030: Group products by categoryId
T-031: Normalize products by id
T-032: Lookup product name and category by id
T-033: Increase all prices by 10% immutably
T-034: Count products per category name
T-035: Log name and category with for...of
T-036: Implement pick
T-037: Implement omit
T-038: Deep merge defaults and overrides
T-039: Implement shallowEqual
T-040: Convert categories object to Map

3. Map, Set & advanced (T-041 – T-048)

#Question
T-041: Create and iterate a Map
T-042: Object to Map via Object.entries
T-043: Map back to plain object
T-044: Deduplicate tags with Set
T-045: Count word occurrences
T-046: Object.create with inherited greet
T-047: When to use Map instead of object
T-048: Safe JSON parse with fallback

1. Fundamentals (T-001 – T-020)

T-001: Create a user object using an object literal

Answer:

Note

Use curly braces with key-value pairs. Keys are strings (or symbols); values can be any type.

javascript
const user = {
  id: 1,
  name: 'Alice',
  email: 'alice@example.com',
  role: 'admin',
}

Back to index


T-002: Create an object using new Object()

Answer:

Note

Instantiate an empty object, then assign properties. Literals are preferred in production code.

javascript
const user = new Object()
user.id = 1
user.name = 'Alice'
user.email = 'alice@example.com'

Back to index


T-003: Access property with dot and bracket notation

Answer:

Note

Dot notation for known keys; bracket notation when the key is stored in a variable or contains special characters.

javascript
const user = { name: 'Alice', role: 'admin' }
 
user.name // 'Alice'
user['role'] // 'admin'
 
const key = 'name'
user[key] // 'Alice'

Back to index


T-004: Add and update properties

Answer:

Note

Assign to a new key to add; assign to an existing key to update. Objects are mutable by default.

javascript
const product = { id: 1, name: 'Mug' }
 
product.price = 12.99 // add
product.name = 'Ceramic Mug' // update

Back to index


T-005: Delete a property with delete

Answer:

Note

delete removes an own property. Returns true if successful.

javascript
const user = { id: 1, name: 'Alice', temp: true }
delete user.temp
console.log(user) // { id: 1, name: 'Alice' }

Back to index


T-006: Check property with in vs Object.hasOwn

Answer:

Note

in checks the whole prototype chain. Object.hasOwn checks own properties only.

javascript
const user = { name: 'Alice' }
 
'name' in user // true
'toString' in user // true — inherited!
Object.hasOwn(user, 'name') // true
Object.hasOwn(user, 'toString') // false

Back to index


T-007: Destructure name and email

Answer:

Note

Pull specific properties into variables in one line.

javascript
const user = { id: 1, name: 'Alice', email: 'alice@example.com' }
const { name, email } = user

Back to index


T-008: Destructure with rename and default

Answer:

Note

Rename with key: newName. Default applies when the property is undefined or missing.

javascript
const user = { name: 'Alice' }
const { name: userName, role = 'viewer' } = user
// userName = 'Alice', role = 'viewer'

Back to index


T-009: Rest destructuring to omit password

Answer:

Note

Rest collects remaining properties — classic omit pattern for API responses.

javascript
const user = { id: 1, name: 'Alice', password: 'secret', role: 'admin' }
const { password, ...safeUser } = user
// safeUser = { id: 1, name: 'Alice', role: 'admin' }

Back to index


T-010: Nested destructuring

Answer:

Note

Match the nested shape in the destructuring pattern.

javascript
const data = {
  user: { address: { city: 'NYC', zip: '10001' } },
}
 
const {
  user: {
    address: { city },
  },
} = data
console.log(city) // 'NYC'

Back to index


T-011: Shallow clone with spread

Answer:

Note

Spread copies top-level keys into a new object. Nested objects are still shared.

javascript
const original = { a: 1, nested: { b: 2 } }
const clone = { ...original }
 
clone.a = 99
original.a // 1 — top-level independent

Back to index


T-012: Deep clone with structuredClone

Answer:

Note

structuredClone recursively copies nested objects and arrays.

javascript
const original = { a: 1, nested: { b: 2 } }
const deep = structuredClone(original)
 
deep.nested.b = 99
original.nested.b // 2 — unchanged

Back to index


T-013: Merge configs with spread

Answer:

Note

Later spread sources overwrite earlier keys for the same property name.

javascript
const defaults = { theme: 'light', pageSize: 10 }
const overrides = { pageSize: 25, lang: 'en' }
 
const config = { ...defaults, ...overrides }
// { theme: 'light', pageSize: 25, lang: 'en' }

Back to index


T-014: Object.assign vs spread

Answer:

Note

Both shallow-merge. Object.assign mutates the first argument and returns it. Spread creates a new object.

javascript
const defaults = { a: 1, b: 2 }
const extra = { b: 3, c: 4 }
 
const target = {}
Object.assign(target, defaults, extra) // mutates target
 
const merged = { ...defaults, ...extra } // new object

Back to index


T-015: Object.keys, values, entries

Answer:

Note

Three static methods to list own enumerable string-keyed properties in different forms.

javascript
const scores = { alice: 90, bob: 75 }
 
Object.keys(scores) // ['alice', 'bob']
Object.values(scores) // [90, 75]
Object.entries(scores) // [['alice', 90], ['bob', 75]]

Back to index


T-016: Object.fromEntries

Answer:

Note

Inverse of entries — builds an object from [key, value] pairs.

javascript
const pairs = [
  ['x', 1],
  ['y', 2],
  ['z', 3],
]
const obj = Object.fromEntries(pairs)
// { x: 1, y: 2, z: 3 }

Back to index


T-017: Loop with Object.entries and for...of

Answer:

Note

Preferred over for...in — no inherited keys, destructuring-friendly.

javascript
const user = { name: 'Alice', role: 'admin' }
 
for (const [key, value] of Object.entries(user)) {
  console.log(key, value)
}

Back to index


T-018: freeze vs seal vs preventExtensions

Answer:

Note

preventExtensions — no new keys. seal — no add/delete, can change values. freeze — no add/delete/change (shallow).

javascript
const obj = { a: 1 }
 
Object.preventExtensions(obj) // can't add keys
Object.seal(obj) // can't add/delete
Object.freeze(obj) // can't add/delete/change values

Back to index


T-019: Read-only property with defineProperty

Answer:

Note

Set writable: false to prevent value changes.

javascript
const user = {}
Object.defineProperty(user, 'id', {
  value: 1,
  writable: false,
  enumerable: true,
  configurable: false,
})

Back to index


T-020: Optional chaining and nullish coalescing

Answer:

Note

?. short-circuits on null/undefined. ?? defaults only for null/undefined, not 0 or ''.

javascript
const user = { profile: { name: 'Alice' } }
 
user.profile?.name // 'Alice'
user.address?.city // undefined
user.address?.city ?? 'Remote' // 'Remote'

Back to index


2. Product dataset (T-021 – T-040)

Shared setup:

javascript
const products = [
  { id: 'p1', name: 'Mug', categoryId: 'c1', price: 12.99, inStock: true },
  { id: 'p2', name: 'Book', categoryId: 'c2', price: 24.5, inStock: true },
  { id: 'p3', name: 'Pen', categoryId: 'c1', price: 2.99, inStock: false },
  { id: 'p4', name: 'Lamp', categoryId: 'c3', price: 45.0, inStock: true },
  { id: 'p5', name: 'Notebook', categoryId: 'c2', price: 8.5, inStock: true },
  { id: 'p6', name: 'Desk', categoryId: 'c3', price: 199.99, inStock: false },
]
 
const categories = { c1: 'Kitchen', c2: 'Stationery', c3: 'Furniture' }
 
const getCategoryName = (id) => categories[id] ?? 'Unknown'
const getCategoryIdByName = (name) => Object.entries(categories).find(([, n]) => n === name)?.[0]

T-021: Filter products in "Stationery" category

Answer:

Note

Resolve category id from name, then filter products.

javascript
const stationeryId = getCategoryIdByName('Stationery') // 'c2'
 
const stationeryProducts = products.filter((p) => p.categoryId === stationeryId)
// Book, Notebook

Back to index


T-022: Format as "Mug (Kitchen)"

Answer:

Note

Map each product to a label string using category lookup.

javascript
const labeled = products.map((p) => `${p.name} (${getCategoryName(p.categoryId)})`)

Back to index


T-023: Find highest-priced product

Answer:

Note

Reduce to track max, or sort a copy and take first (reduce is O(n)).

javascript
const highest = products.reduce((max, p) => (p.price > max.price ? p : max))
// Desk — 199.99

Back to index


T-024: Any product out of stock?

Answer:

Note

some returns true if at least one matches.

javascript
const hasOutOfStock = products.some((p) => !p.inStock)
// true

Back to index


T-025: Function filterByMinPrice

Answer:

Note

Reusable filter with a price threshold parameter.

javascript
function filterByMinPrice(list, minPrice) {
  return list.filter((p) => p.price > minPrice)
}
 
filterByMinPrice(products, 20)
// Book, Lamp, Desk

Back to index


T-026: Extract product names only

Answer:

Note

map to pluck the name field.

javascript
const names = products.map((p) => p.name)

Back to index


T-027: Total value of in-stock products

Answer:

Note

Filter in-stock, then reduce prices.

javascript
const totalInStock = products.filter((p) => p.inStock).reduce((sum, p) => sum + p.price, 0)
// 91.99

Back to index


T-028: Any product priced below 5?

Answer:

Note

some with price comparison.

javascript
const hasCheap = products.some((p) => p.price < 5)
// true — Pen (2.99)

Back to index


T-029: Find product with price exactly 8.5

Answer:

Note

find returns first match or undefined.

javascript
const notebook = products.find((p) => p.price === 8.5)

Back to index


T-030: Group products by categoryId

Answer:

Note

Object.groupBy (ES2024) groups array items by key function.

javascript
const byCategory = Object.groupBy(products, (p) => p.categoryId)
// { c1: [Mug, Pen], c2: [Book, Notebook], c3: [Lamp, Desk] }

Back to index


T-031: Normalize products by id

Answer:

Note

Convert array to object keyed by id for O(1) lookup — common Redux pattern.

javascript
const productsById = Object.fromEntries(products.map((p) => [p.id, p]))
 
productsById['p4'].name // 'Lamp'

Back to index


T-032: Lookup product name and category by id

Answer:

Note

Combine normalized lookup with categories map.

javascript
function getProductDetails(id) {
  const product = productsById[id]
  if (!product) return null
  return {
    name: product.name,
    category: getCategoryName(product.categoryId),
  }
}

Back to index


T-033: Increase all prices by 10% immutably

Answer:

Note

map returns new objects — source array unchanged.

javascript
const withMarkup = products.map((p) => ({
  ...p,
  price: +(p.price * 1.1).toFixed(2),
}))

Back to index


T-034: Count products per category name

Answer:

Note

Reduce into an accumulator object, incrementing counts.

javascript
const countByCategory = products.reduce((acc, p) => {
  const name = getCategoryName(p.categoryId)
  acc[name] = (acc[name] ?? 0) + 1
  return acc
}, {})
// { Kitchen: 2, Stationery: 2, Furniture: 2 }

Back to index


T-035: Log name and category with for...of

Answer:

Note

Build a lookup map first, then iterate entries.

javascript
const labelMap = Object.fromEntries(
  products.map((p) => [p.id, { name: p.name, category: getCategoryName(p.categoryId) }]),
)
 
for (const [id, info] of Object.entries(labelMap)) {
  console.log(id, info.name, info.category)
}

Back to index


T-036: Implement pick

Answer:

Note

Select only specified keys into a new object.

javascript
function pick(obj, keys) {
  return Object.fromEntries(keys.filter((k) => k in obj).map((k) => [k, obj[k]]))
}
 
products.map((p) => pick(p, ['id', 'name', 'price']))

Back to index


T-037: Implement omit

Answer:

Note

Exclude specified keys from a new object.

javascript
function omit(obj, keys) {
  const exclude = new Set(keys)
  return Object.fromEntries(Object.entries(obj).filter(([k]) => !exclude.has(k)))
}
 
products.map((p) => omit(p, ['inStock']))

Back to index


T-038: Deep merge defaults and overrides

Answer:

Note

Recursively merge nested objects; override leaf values from overrides.

javascript
function deepMerge(target, source) {
  const out = { ...target }
  for (const [key, value] of Object.entries(source)) {
    if (value && typeof value === 'object' && !Array.isArray(value) && target[key] && typeof target[key] === 'object') {
      out[key] = deepMerge(target[key], value)
    } else {
      out[key] = value
    }
  }
  return out
}
 
const defaults = { theme: 'light', settings: { fontSize: 14, bold: false } }
const overrides = { settings: { fontSize: 16 } }
 
deepMerge(defaults, overrides)
// { theme: 'light', settings: { fontSize: 16, bold: false } }

Back to index


T-039: Implement shallowEqual

Answer:

Note

Compare key count and each value with Object.is.

javascript
function shallowEqual(a, b) {
  if (Object.is(a, b)) return true
  if (!a || !b || typeof a !== 'object' || typeof b !== 'object') return false
  const keysA = Object.keys(a)
  const keysB = Object.keys(b)
  if (keysA.length !== keysB.length) return false
  return keysA.every((key) => Object.is(a[key], b[key]))
}

Back to index


T-040: Convert categories object to Map

Answer:

Note

Object.entries + Map constructor.

javascript
const categoryMap = new Map(Object.entries(categories))
categoryMap.get('c2') // 'Stationery'

Back to index


3. Map, Set & advanced (T-041 – T-048)

T-041: Create and iterate a Map

Answer:

Note

Map accepts any key type and preserves insertion order.

javascript
const map = new Map()
map.set('name', 'Alice')
map.set(42, 'answer')
map.set({ id: 1 }, 'meta')
 
for (const [key, value] of map) {
  console.log(key, value)
}

Back to index


T-042: Object to Map via Object.entries

Answer:

Note

Standard conversion for when you need Map APIs on plain data.

javascript
const obj = { a: 1, b: 2 }
const map = new Map(Object.entries(obj))

Back to index


T-043: Map back to plain object

Answer:

Note

Object.fromEntries accepts iterable of pairs — map.entries() works.

javascript
const map = new Map([
  ['a', 1],
  ['b', 2],
])
const obj = Object.fromEntries(map)
// { a: 1, b: 2 }

Back to index


T-044: Deduplicate tags with Set

Answer:

Note

Set stores unique values; spread back to array.

javascript
const tags = ['js', 'web', 'js', 'api', 'web']
const unique = [...new Set(tags)]
// ['js', 'web', 'api']

Back to index


T-045: Count word occurrences

Answer:

Note

Use object (or Map) as frequency map.

javascript
const sentence = 'the cat and the dog'
const counts = {}
 
for (const word of sentence.split(' ')) {
  counts[word] = (counts[word] ?? 0) + 1
}
// { the: 2, cat: 1, and: 1, dog: 1 }

Back to index


T-046: Object.create with inherited greet

Answer:

Note

Set prototype to an object with shared methods.

javascript
const personProto = {
  greet() {
    return `Hi, I'm ${this.name}`
  },
}
 
const user = Object.create(personProto)
user.name = 'Alice'
user.greet() // "Hi, I'm Alice"

Back to index


T-047: When to use Map instead of object

Answer:

Note

Use Map when keys are not strings/symbols, you need frequent add/delete, or you want a clean prototype-free store.

javascript
// DOM node → metadata (object keys get coerced to strings)
const nodeData = new Map()
const el = document.createElement('div')
nodeData.set(el, { clicks: 0 }) // object as key works

Back to index


T-048: Safe JSON parse with fallback

Answer:

Note

Wrap JSON.parse in try/catch; return fallback on invalid JSON.

javascript
function safeParse(json, fallback = null) {
  try {
    return JSON.parse(json)
  } catch {
    return fallback
  }
}
 
safeParse('{"a":1}') // { a: 1 }
safeParse('not json', {}) // {}

Back to index


Quick reference — method by task

TasksPrimary APIs
T-001 – T-006literals, dot/bracket, delete, in, Object.hasOwn
T-007 – T-010destructuring, rest, nested destructuring
T-011 – T-014spread, structuredClone, Object.assign
T-015 – T-020Object.keys/values/entries/fromEntries, freeze/seal, defineProperty, ?.
T-021 – T-040filter, map, reduce, Object.groupBy, normalize, pick/omit
T-041 – T-048Map, Set, Object.create, safe JSON parse

Interview tip: Practice explaining T-006 (in vs hasOwn), T-031 (normalization), and T-047 (Map vs Object) aloud.

Share this article

XLinkedInFacebook
Kazi Rahamatullah

Written by

Kazi Rahamatullah

FullStack Developer

X / TwitterGitHubLinkedIn

Subscribe to my newsletter

Stay up to date and get notified when I share new contents.

No spam ever, unsubscribe anytime