如何用JavaScript(可使用Underscore)遍历嵌套JSON对象并追踪父子层级
Great question! Traversing deeply nested objects while keeping tabs on your current position in the hierarchy is a super common task—here’s how to pull it off cleanly with vanilla JavaScript or Underscore.js.
First, let’s use your sample object for reference:
const nestedData = { 'parent1': { 'name': 'something', 'children': { 'name': 'something else' } }, 'parent2': { 'name': 'something', 'children': { 'name': 'something else', 'anotherProp': { 'name': 'whoa..somethin...' } } } };
Vanilla JavaScript Solution
A recursive function is the most straightforward approach here. We’ll track two key pieces of hierarchy info:
currentDepth: A number representing how many levels deep we are (root level = 1)path: An array that builds out the full parent-child chain (e.g.,['parent2', 'children', 'anotherProp'])
Here’s the implementation:
function traverseNestedObj(obj, currentDepth = 1, path = []) { // Loop through all keys in the current object for (const key of Object.keys(obj)) { const value = obj[key]; // Build the full path to the current key const currentPath = [...path, key]; // Example output: log the hierarchy and value console.log(`Level: ${currentDepth}, Path: ${currentPath.join(' -> ')}, Value: ${typeof value === 'object' ? '[Object]' : value}`); // If the value is a non-null object, recurse deeper if (typeof value === 'object' && value !== null) { traverseNestedObj(value, currentDepth + 1, currentPath); } } } // Run the traversal traverseNestedObj(nestedData);
When you run this, you’ll get clear output showing exactly where you are in the hierarchy at every step.
Underscore.js Solution
If you’re already using Underscore, you can simplify the loop with _.each and use _.isObject for cleaner type checking:
function traverseWithUnderscore(obj, currentDepth = 1, path = []) { _.each(obj, (value, key) => { const currentPath = [...path, key]; console.log(`Level: ${currentDepth}, Path: ${currentPath.join(' -> ')}, Value: ${_.isObject(value) ? '[Object]' : value}`); // Recurse only if the value is a valid non-null object if (_.isObject(value) && value !== null) { traverseWithUnderscore(value, currentDepth + 1, currentPath); } }); } // Run the traversal traverseWithUnderscore(nestedData);
Handling Edge Cases
If your object might have circular references (an object that references itself somewhere in the hierarchy), you’ll need to add a check to avoid infinite recursion. We can use a WeakSet to track visited objects:
function traverseWithCircularCheck(obj, currentDepth = 1, path = [], visited = new WeakSet()) { // Skip if we've already processed this object if (visited.has(obj)) return; visited.add(obj); for (const key of Object.keys(obj)) { const value = obj[key]; const currentPath = [...path, key]; console.log(`Level: ${currentDepth}, Path: ${currentPath.join(' -> ')}, Value: ${typeof value === 'object' ? '[Object]' : value}`); if (typeof value === 'object' && value !== null) { traverseWithCircularCheck(value, currentDepth + 1, currentPath, visited); } } }
This way, you’ll never hit a stack overflow from circular references.
You can tweak the logging/processing logic to fit your needs—whether you’re collecting data from a specific level, modifying properties, or just auditing the structure.
内容的提问来源于stack exchange,提问作者Steve Rogers

