0

What i'm trying to achieve is to create a function that would help me to quickly check the existance of a given property within a deeply nested javascript object, api or library and return the results as relevant paths such as: root/child/child/match.

Here's what i've got so far:

function findNode(obj, str) {
    var results = [], regx = new RegExp(str, "gi");

    function innerFind(obj, str, currentPath) {
        var i, propName, prop, result;

        if (toString.call(obj) === "[object Array]") {
            for (i = 0; i < obj.length; i++) {
                if (typeof obj[i] === "object") {
                    innerFind(obj[i], str, currentPath + "[" + i + "]/");
                }
            }

        } else {
            for (propName in obj) {
                if (regx.test(propName)) {
                    results.push(currentPath + propName + "/");
                }

                prop = obj[propName];
                if (typeof prop === "object") {
                    innerFind(prop, str, currentPath + propName + "/");
                }
            }
        }
    }

    if (typeof obj === "object") {
        innerFind(obj, str, "root/");
    }

    return results;
}

It works perfectly on small to medium sized objects, however it fails on larger objects with the error: RangeError: Maximum call stack size exceeded. I understand that the error was thrown because the function innerFind was called numerous times from within itself.

So my question is, how to make the above function work without getting the RangeError error? and is there a better more efficient way of doing this?

razz
  • 9,770
  • 7
  • 50
  • 68
  • +1 Nice question, well formatted, good effort, all the things. – MarioDS Jun 04 '14 at 18:56
  • 1
    Without stepping through every aspect of your code, what I am guessing is, that the "larger objects" that you tried your function on might have recursive references in them. Have you ever tried running those objects that break your code with `JSON.stringify(obj)`? – Amberlamps Jun 04 '14 at 19:00
  • The callstack limits are [pretty high](http://stackoverflow.com/questions/7826992/browser-javascript-stack-size-limit). How deeply nested were these objects? @amberlamps may be right about circular references. – James Montagne Jun 04 '14 at 19:05
  • @Amberlamps it throws this error when i try to json stringify it `TypeError: Converting circular structure to JSON` – razz Jun 04 '14 at 19:06
  • @JamesMontagne its a huge library and deeply nested. – razz Jun 04 '14 at 19:09
  • Well, there you have it. Does this answer your question? – Amberlamps Jun 04 '14 at 19:13
  • No not really, i still need to fix it or to find a way around it! – razz Jun 04 '14 at 19:15

1 Answers1

1

There is a circular reference within your "large" object that your are trying to resolve. If you don´t know what a circular reference is, here is an example:

var obj = {
    child: null
}
obj.child = obj;

You will not be able to run your function with that object, because it has a reference to itself making you script run forever and ultimatively exceed stack size.

It is difficult to "fix" your function, because it is anything but easy to find those references. Those circular references themselves can be very complex.

Amberlamps
  • 39,180
  • 5
  • 43
  • 53