Skip to content

Instantly share code, notes, and snippets.

@snydergd
Created September 1, 2016 03:58
Show Gist options
  • Save snydergd/8d6b361cd698a7d3046505b2491116a3 to your computer and use it in GitHub Desktop.
Save snydergd/8d6b361cd698a7d3046505b2491116a3 to your computer and use it in GitHub Desktop.
Javascript Cyclic Nested Object Property Search
/*
* Finds locations within data structure that a specific key/value can be found
* - Handles looping data structures (for instance window.window = window)
* - Flexible query format (provide key to match, value to match, or both)
* - Handy for reverse engineering and understanding javascript code on websites
* - Note, it's a little hack-ish, but it's just a tool anyway
* Examples:
* a = {b: 4, c: [1, 2, {d: 5, e: [0, 5, 2]}]};
* searchObj(a, {key: d}); // --> ["root.c.2.d"]
* searchObj(a, {value: 2}); // --> ["root.c.1", "root.c.2.e.2"]
* searchObj(a, {key: 1, value: 2}); // --> ["root.c.1"]
**/
var searchObj = (function () {
var uniqueId = 0;
return function(obj, query) {
if (!("key" in query || "value" in query)) return -1;
var stack = [[["root", obj]]]; // remaining tree to traverse
var objStack = []; // current object path
var i;
var visited = {}; // handle cycles
result = []; // object paths found
function addResult(last) {
var i, r = [];
for (i in objStack) r.push(objStack[i]);
r.push(last);
result.push(r.join("."));
}
while (stack.length > 0) {
if (stack[stack.length-1].length == 0) {
stack.pop();
if (objStack.length) objStack.pop();
continue;
}
obj = stack[stack.length-1].pop();
if (!obj[1].hasOwnProperty('unique_id')) Object.defineProperty(obj[1], 'unique_id', {value: uniqueId++}); // non-iterable property
visited[obj[1].unique_id] = true;
objStack.push(obj[0]);
stack.push([]);
for (var t in Object.getOwnPropertyNames(obj[1])) {
i = Object.getOwnPropertyNames(obj[1])[t];
try {
if ((!("key" in query) || query["key"] == i) &&
(!("value" in query) || query["value"] == obj[1][i]))
addResult(i);
if (typeof(obj[1][i]) == "object" && obj[1][i] != null && (!("unique_id" in obj[1][i]) || !visited[obj[1][i].unique_id])) {
stack[stack.length-1].push([i, obj[1][i]]);
}
} catch (exception) {
console.log("Caught exception on " + objStack.concat([i]).join(".") + ": " + exception);
}
}
}
return result;
}})();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment