Hone logo
Hone
Problems

Nested Object Iterator in JavaScript

This challenge asks you to create a custom iterator for a nested JavaScript object. Iterators provide a standardized way to traverse collections of data, and implementing one for a nested object allows you to systematically access its values regardless of the depth of nesting. This is useful for tasks like data validation, transformation, or reporting on complex data structures.

Problem Description

You need to create a JavaScript class called NestedObjectIterator that can iterate over the values of a nested JavaScript object. The iterator should traverse the object recursively, yielding each value encountered. The iterator should handle objects, arrays, and primitive values within the nested structure.

What needs to be achieved:

  • Create a class NestedObjectIterator that implements the iterator protocol.
  • The iterator should accept a nested object as input during instantiation.
  • The iterator should have a next() method that returns an object with value and done properties, following the iterator protocol.
  • The next() method should recursively traverse the object, yielding the value of each non-object, non-array element.
  • When the end of the object is reached, the next() method should return { done: true, value: undefined }.

Key Requirements:

  • The iterator must adhere to the JavaScript iterator protocol.
  • The iterator must handle both objects and arrays within the nested structure.
  • The iterator should only yield primitive values (strings, numbers, booleans, null, undefined).
  • The iterator should not yield objects or arrays themselves.

Expected Behavior:

The iterator should yield values in a depth-first traversal order. For example, if the input object has nested arrays and objects, the values within the innermost elements should be yielded first.

Edge Cases to Consider:

  • Empty objects and arrays.
  • Circular references (the iterator should not enter an infinite loop). While not strictly required to handle circular references perfectly (e.g., detecting them), the iterator should not crash or loop indefinitely.
  • Objects containing null and undefined values. These should be treated as primitive values and yielded.
  • Input that is not an object (e.g., a string, number, or boolean). The iterator should handle this gracefully, potentially by returning { done: true, value: undefined } immediately.

Examples

Example 1:

Input: { a: 1, b: { c: 2, d: [3, 4] } }
Output: Iterator yields: 1, 2, 3, 4
Explanation: The iterator traverses the object depth-first, yielding the values 1, 2, 3, and 4.

Example 2:

Input: { a: "hello", b: [1, { c: "world" }, 2], d: null }
Output: Iterator yields: "hello", 1, "world", 2, null
Explanation: The iterator yields the primitive values "hello", 1, "world", 2, and null.

Example 3:

Input: {}
Output: Iterator yields: undefined (and done: true)
Explanation: The object is empty, so the iterator immediately returns { done: true, value: undefined }.

Constraints

  • The input object can have arbitrary nesting depth.
  • The input object can contain any valid JavaScript data types.
  • The iterator should be reasonably performant for objects with a moderate number of nested levels (up to 10). Optimization for extremely deep nesting is not a primary concern.
  • The input object will always be a plain JavaScript object (no prototypes modified).

Notes

  • Remember to implement the Symbol.iterator method on your NestedObjectIterator class to make it iterable.
  • Consider using recursion to traverse the nested object.
  • Think about how to handle circular references to prevent infinite loops. A simple check to see if a key has already been visited can prevent this.
  • The next() method should return an object with value and done properties, as required by the iterator protocol. done should be true when there are no more values to yield.
Loading editor...
javascript