Keywords: JavaScript | Object | Recursion | PropertyPath
Abstract: This article explores how to recursively traverse JavaScript objects to build a list of property paths showing hierarchy. It analyzes the recursive function from the best answer, explaining principles, implementation, and code examples, with brief references to other answers as supplementary material.
Problem Description
When dealing with complex JavaScript objects, it is often necessary to traverse all properties and build a list of paths showing hierarchical relationships. For example, given an object, output paths like aProperty.aSetting1.
The original problem provided an example object:
var object = {
aProperty: {
aSetting1: 1,
aSetting2: 2,
aSetting3: 3,
aSetting4: 4,
aSetting5: 5
},
bProperty: {
bSetting1: {
bPropertySubSetting : true
},
bSetting2: "bString"
},
cProperty: {
cSetting: "cString"
}
}
The goal is to build a list as follows:
aProperty.aSetting1
aProperty.aSetting2
aProperty.aSetting3
aProperty.aSetting4
aProperty.aSetting5
bProperty.bSetting1.bPropertySubSetting
bProperty.bSetting2
cProperty.cSetting
Basic Concepts of Recursive Traversal
Recursion is a programming technique where a function calls itself to solve a problem. In object traversal, recursion can be used to delve into sub-objects until primitive data types are encountered, implementing depth-first search.
Solution Analysis
Based on the best answer, an effective recursive function iterate uses a stack parameter to track the current path. It recursively calls for object properties and outputs the full path otherwise.
function iterate(obj, stack) {
for (var property in obj) {
if (obj.hasOwnProperty(property)) {
if (typeof obj[property] == "object") {
iterate(obj[property], stack + "." + property);
} else {
console.log(property + " " + obj[property]);
// Assume an output element for displaying paths
$("#output").append($("<div/>").text(stack + "." + property));
}
}
}
}
iterate(object, '');
In the function, stack starts as an empty string and accumulates property names recursively, building paths like aProperty.aSetting1. Note: The typeof check may exclude null or arrays, and adjustments should be made based on actual data types.
Code Explanation
The function uses a for...in loop to iterate over object properties, filtering with hasOwnProperty to avoid prototype chain properties. Recursive calls pass the updated stack to ensure path accumulation. The output part can be replaced with array storage or other processing methods.
Supplementary References
Other answers provide alternative approaches, such as using Object.entries and reduce to return a path array, suitable for more complex objects.
function propertiesToArray(obj) {
const isObject = val =>
val && typeof val === 'object' && !Array.isArray(val);
const addDelimiter = (a, b) =>
a ? `${a}.${b}` : b;
const paths = (obj = {}, head = '') => {
return Object.entries(obj)
.reduce((product, [key, value]) =>
{
let fullPath = addDelimiter(head, key);
return isObject(value) ?
product.concat(paths(value, fullPath))
: product.concat(fullPath);
}, []);
}
return paths(obj);
}
This solution returns a path array, facilitating further operations like sorting or filtering.
Conclusion
Recursive traversal is a powerful tool for handling nested object structures, enabling efficient generation of property lists through path stacking. Developers should choose between simple recursion or more complex array methods based on needs, and handle data types carefully to avoid errors.