14

假设我想'StackOverflow'在所有声明的变量中搜索一个值,比如window. 我可以用这段代码做到这一点:

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

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

我的问题是我想更深入地搜索 thruwindow的对象(以及它自己的嵌套对象),以获得如下结果:

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

我在继承对象的方法时遇到问题。有没有办法做到这一点?

4

4 回答 4

26

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

函数递归具有内部堆栈限制并浪费内存。

添加的附加功能

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

如果对象本身与值匹配,则返回 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 是一页长的。或者,我们只能使用尖括号,但这对于 OPs 的原始问题并不真实。

对数组“搜索”的 indexOf 调用对于非常大的对象可能有点重,但我还想不出替代方案。

改进

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

于 2012-08-24T04:25:29.783 回答
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;
}
于 2012-08-24T02:26:58.917 回答
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');

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

于 2012-08-24T02:28:11.593 回答
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);
}
于 2019-06-06T02:18:55.560 回答