JavaScript: Array and Object Advanced Methods

Master map, filter, reduce, method chaining, Object utilities, and every copying strategy from shallow to deep.

map(): Transform Every Element

map() creates a new array by running a callback on every element. The original array is never mutated.

map()

Use map() whenever you need a new array of the same length with each element transformed.

  • Always returns a new array of the same length as the input
  • The callback receives (element, index, array)
  • Common patterns: extract a field, format values, convert types
  • Chain with filter() to transform only matching items

map() Patterns

Extract fields, add computed properties, or convert values, always a new array.

filter(): Keep Matching Elements

filter() creates a new array containing only the elements for which the callback returns a truthy value.

filter()

Use filter() to narrow down a dataset, the result may be shorter than the input.

  • Returns a new array with 0 to n elements never mutates the original
  • The callback receives (element, index, array) and must return truthy/falsy
  • Chain with map() to filter then transform
  • Use Boolean as the callback to remove all falsy values: .filter(Boolean)

filter() Patterns

Keep only elements that satisfy a condition, chain with map() for transform-after-filter.

reduce(): Accumulate to a Single Value

reduce() iterates over an array and accumulates a result, the most powerful and flexible array method.

reduce(callback, initialValue)

reduce() can produce any output type: a number, string, object, or array.

  • Callback receives (accumulator, currentValue, index, array)
  • Always provide an initial value as the second argument to avoid bugs on empty arrays
  • Can replace any combination of map + filter when performance is critical
  • Common uses: sum, groupBy, counting, flattening, building objects from arrays

reduce() Patterns

Sum totals or group data into objects, the accumulator can be any shape.

Method Chaining

Because array methods return new arrays, you can chain them directly without intermediate variables. The result of one method becomes the input of the next.

Method Chaining

Chains read as a pipeline, each step passes its result to the next without storing it in a variable.

  • Read left-to-right as a data pipeline: source → filter → map → reduce
  • Each chained method receives the output of the previous one
  • Break long chains onto multiple lines for readability
  • Profile before optimising, a single reduce() can replace a filter + map chain if performance matters

Method Chaining Pipeline

Chain filter, map, and reduce into a readable data pipeline.

Object.keys(), Object.values(), Object.entries()

These three static methods convert an object's structure into arrays, making it easy to iterate, filter, or transform object data using array methods.

Object to Array Conversions

Converting objects to arrays unlocks the full power of map, filter, and reduce on object data.

  • Object.keys(obj): array of own enumerable property names
  • Object.values(obj): array of own enumerable property values
  • Object.entries(obj): array of [key, value] pairs
  • All three only return own enumerable properties, inherited ones are excluded

Object.keys / values / entries

Convert object data into arrays to use filter, map, and reduce on it.

Object.fromEntries()

Object.fromEntries() is the inverse of Object.entries(), it converts an array of [key, value] pairs back into an object.

Object.fromEntries()

Combine with Object.entries() and map() to transform object properties cleanly.

  • Accepts any iterable of [key, value] pairs, including a Map
  • Perfect for transforming object values: entries → map → fromEntries
  • Replaces the verbose Object.keys().reduce() pattern
  • Also converts a Map directly to a plain object

Object.fromEntries()

Transform object values or filter keys by round-tripping through entries.

Object.getOwnPropertyNames()

Unlike Object.keys(),Object.getOwnPropertyNames() returns all own property names including non-enumerable ones.

Object.getOwnPropertyNames()

Use when you need to inspect hidden or non-enumerable properties that Object.keys() skips.

  • Returns all own property names: enumerable AND non-enumerable
  • Does NOT include Symbol-keyed properties (use Object.getOwnPropertySymbols() for those)
  • Useful for inspecting class instances, methods defined on prototypes are not included
  • Non-enumerable properties are created with Object.defineProperty()

Object.getOwnPropertyNames()

Reveals non-enumerable properties that Object.keys() hides.

Object.defineProperty()

Object.defineProperty() adds or modifies a property with fine-grained control over its behaviour whether it can be written, enumerated, or deleted.

Object.defineProperty()

Use defineProperty when you need to lock down properties or add computed getters to an object.

  • writable: false: value cannot be changed (throws in strict mode)
  • enumerable: false: hidden from for...in and Object.keys()
  • configurable: false: property cannot be deleted or redefined
  • Use get / set descriptor keys to define a getter/setter property

Object.defineProperty()

Create read-only constants or computed getter properties with full descriptor control.

Shallow vs Deep Copying

A shallow copy duplicates the top-level properties but nested objects are still shared references. A deep copy produces a completely independent clone with no shared references at any depth.

Shallow Copy

Object.assign() and spread both create shallow copies modifying nested objects still affects the original.

  • Object.assign({}, source): copies own enumerable properties one level deep
  • { ...source }: same as Object.assign, spread is shallow
  • Safe for flat objects with only primitive values
  • Unsafe if the object contains nested objects, arrays, or Dates

Shallow Copy Limitation

Spread copies the top level only, nested objects are still the same reference.

Deep Copying Strategies

For nested objects you need a deep copy. Three approaches exist, each with trade-offs.

Deep Copy Options

Use structuredClone() in modern environments, it handles dates, sets, maps, and circular references.

  • JSON.parse(JSON.stringify(obj)): simple but loses Dates, functions, undefined, Symbols
  • structuredClone(obj): modern, built-in, handles Date, Map, Set, ArrayBuffer, circular refs
  • Third-party libraries (Lodash _.cloneDeep): handles edge cases, works in older environments
  • For plain data objects with no special types, the JSON trick is still common and fine

Deep Copy Strategies

structuredClone() is the modern choice, JSON trick works for plain serialisable data.

MethodDepthHandles Date / Map / SetCircular refs
{ ...obj } / Object.assign()ShallowNoNo
JSON.parse(JSON.stringify())DeepNo, Dates become stringsNo, throws
structuredClone()DeepYesYes
_.cloneDeep() (Lodash)DeepYesYes

Knowledge Check

1. What does map() return?

2. What does reduce() use as its starting accumulator when no initial value is provided?

3. What does Object.entries() return?

4. What does Object.fromEntries() do?

5. What is the limitation of the spread operator when copying objects?

6. Which method creates a true deep clone of an object including nested structures in modern JS?

7. What is method chaining with array methods?