递归搜索全局变量及其属性中的值

时间:2012-08-24 02:20:27

标签: javascript arrays object global-variables

假设我想在'StackOverflow'中的所有声明变量中搜索值window。 我可以用这段代码来完成:

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

此代码将返回具有此值的变量的名称(或不返回任何内容)。 因此,如果我声明了一个值为'StackOverflow'的变量,它将成功找到它。

我的问题是我想更深入地搜索window的对象(及其自己的嵌套对象),以达到如下结果:

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

我遇到了Object的继承方法问题。有没有办法做到这一点?

4 个答案:

答案 0 :(得分:15)

深度搜索但没有递归函数调用

功能递归具有内部堆栈限制并浪费内存。

添加了其他功能

搜索数组形式的递归对象保护;当然,它不会占用太多内存,因为对象仅存储为引用。

如果对象本身与值匹配,则返回true。否则它将返回''匹配为false。

数组使用角括号表示法。

代码

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;
}

<强>问题

如果不将初始变量名称传递给函数,我们就无法从头开始返回完全限定的变量名称。我想不出解决方案,如果有的话,我会感到惊讶。

带空格的变量名作为对象的键是有效的,其他无效变量名也是如此,它只是意味着必须使用尖括号来处理该值。我能想到几个解决方案。正则表达式检查每个变量名称以确保它是有效的,如果不是,则使用尖括号表示法。最重要的问题是reg-ex是一个页面长。或者,我们只能使用尖括号,但这对于OP原始问题并非如此。

对''搜索'数组的indexOf调用对于非常大的对象可能有点沉重,但我还不能想到另一种选择。

<强>改进

除了清理代码之外,如果函数返回一个匹配数组也会很好。这也引发了另一个问题,即返回的数组不包含对递归对象的引用。也许该函数可以接受结果格式配置参数。

答案 1 :(得分:5)

这应该有效。它使用递归来实现结果。

function globalSearch(obj, value) {
    for(var p in obj)
        if(obj[p] == value){
            return(p);
        }else if(typeof obj[p] == "object" && obj[p] != obj){
           var te = globalSearch(obj[p], value);
           if(te!=false){ return p + "." + te }
        }
    return false;
}

答案 2 :(得分:0)

使您的解决方案递归。如果您有对象,请再次调用您的函数。

function globalSearch(obj, value) {
    for(var p in obj) {
        if (obj[p] == value) {
            return(p);
        } else if (typeof obj[p] === "object") {
            var recursiveCheck= globalSearch(obj[p], value);
            if (recursiveCheck) {
                return p + "." + recursiveCheck;
            }
        }
    }
}
globalSearch(window, 'StackOverflow');

我敢打赌,大多数浏览器会因过多循环而发出警告。

答案 3 :(得分:0)

此代码基于另一个答案,允许找到所有可能的值匹配。

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

    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) {
            if (returnFirstResult) {
                return address == '' ? false : address;
            }
            found.add(address)
        }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 Array.from(found);
}