I really liked Roland Jegorov's answer, but I had a very complex object that I needed to search through and that answer could not account for it.
If you were in a situation like mine you may want to first make sure you have no circular references (or else you'll run into an infinite search). There are a few ways to do this, but I was having to stringify my object to copy it into other windows, so I ended up using this circular replacer: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Errors/Cyclic_object_value
(Update here - I made a small change to the getCircularReplacer function from MDN so it no longer leaves out function references since that is what I was looking for!)
(Update 3 - I also wanted to check on methods of any instances of classes, but I was returning just 'function' too early, so I have adjusted it to include instance methods. I think it finally works as I intended!)
const getCircularReplacer = () => {
const seen = new WeakSet();
return (key, value) => {
if (typeof value === "function") {
if (value?.prototype) {
if (seen.has(value.prototype)) {
return;
}
seen.add(value.prototype)
return value.prototype
}
return "function";
}
if (typeof value === "object" && value !== null) {
if (seen.has(value)) {
return;
}
seen.add(value);
}
return value;
};
};
const nonCyclicObject = JSON.parse(JSON.stringify(myComplexObject, getCircularReplacer()));
Then I used this modified version of Roland's answer:
(Update 2: I had to make sure not to return after the key was found as it would always simply return after only calling the function once if the first level of the object had that key)
function findPathsToKey(options) {
let count = 0;
let results = [];
(function findKey({
key,
obj,
pathToKey,
}) {
count += 1;
if (obj === null) return;
const oldPath = `${pathToKey ? pathToKey + "." : ""}`;
if (Object.hasOwnProperty.call(obj, key)) {
results.push(`${oldPath}${key}`);
}
if (typeof obj === "object" && !Array.isArray(obj)) {
for (const k in obj) {
if (Object.hasOwnProperty.call(obj, k)) {
if (Array.isArray(obj[k])) {
for (let j = 0; j < obj[k].length; j++) {
findKey({
obj: obj[k][j],
key,
pathToKey: `${oldPath}${k}[${j}]`,
});
}
}
if (typeof obj[k] === "object") {
findKey({
obj: obj[k],
key,
pathToKey: `${oldPath}${k}`,
});
}
}
}
}
})(options);
return { count, results };
};
The count was just to troubleshoot a little bit and make sure it was actually running through the amount of keys I thought it was. Hope this helps any others looking for a solution!