Welcome to ShenZhenJia Knowledge Sharing Community for programmer and developer-Open, Learning and Share
menu search
person
Welcome To Ask or Share your Answers For Others

Categories

Let's say that I want to search for a value, like 'StackOverflow', in all declared variables in window. I can do it with this code:

function globalSearch(obj, value) {
    for(var p in obj)
        if(obj[p] == value)
            return(p);
}
globalSearch(window, 'StackOverflow');

This code will return the name of a variable that have this value (or returns nothing). So, if I have declared a variable with value 'StackOverflow', it will successfully find it.

My problem is that I want to go deeper and search thru window's objects (and its own nested objects) too, to achieve a result like this:

var x = 'StackOverflow'                     // returns 'x'
var y = { a : 'StackOverflow' }             // returns 'y.a'
var z = { a : { b: 'StackOverflow' } }      // returns 'z.a.b'

I'm having problems with inherited methods of Objects. Is there a way to do this?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
thumb_up_alt 0 like thumb_down_alt 0 dislike
184 views
Welcome To Ask or Share your Answers For Others

1 Answer

Deep search but without the recursive function calls

Functional recursion has internal stack limits and wastes memory.

Additional features added

Recursive object protection in the form of a searched array; It doesn't use up too much memory of course as the objects are only stored as references.

Return true if the the object itself matches the value. Otherwise it would return '' which would match to false.

Arrays use angle-bracket notation.

The code

function globalSearch(startObject, value) {
    var stack = [[startObject,'']];
    var searched = [];
    var found = false;

    var isArray = function(test) {
        return Object.prototype.toString.call( test ) === '[object Array]';
    }

    while(stack.length) {
        var fromStack = stack.pop();
        var obj = fromStack[0];
        var address = fromStack[1];

        if( typeof obj == typeof value && obj == value) {
            var found = address;
            break;
        }else if(typeof obj == "object" && searched.indexOf(obj) == -1){
           if ( isArray(obj) ) {
              var prefix = '[';
              var postfix = ']';
           }else {
              var prefix = '.';
              var postfix = '';
           }
           for( i in obj ) {
              stack.push( [ obj[i], address + prefix + i + postfix ] );
           }
           searched.push(obj);
        }
    }
    return found == '' ? true : found;
}

Problems

Without passing the intial variable name into the function, we can't return the fully qualified variable name from the beginning. I can't think of a solution and I woud be surprised if there was one.

Variable names with spaces are valid as the key to an object, as are other invalid variable names, it just means that the value must be addressed using angle-brackets. There are a couple of solutions I can think of. Regex check each variable name to make sure it's valid and use angle-brackets notation if it is not. The overriding problem with this is that the reg-ex is a page long. Alternatively, we could only use angle-brackets but this isn't really true to the OPs original question.

The indexOf call on the array 'searched' might be a bit heavy on very large objects but I can't yet think of an alternative.

Improvements

Apart from cleaning up the code a little, it would also be nice if the function returned an array of matches. This also raises another issue in that the returned array would not contain references to recursive objects. Maybe the function could accept a result format configuration parameter.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
thumb_up_alt 0 like thumb_down_alt 0 dislike
Welcome to ShenZhenJia Knowledge Sharing Community for programmer and developer-Open, Learning and Share
...