开发者问题收集

在 javascript 对象中搜索具有特定值的属性?

2012-02-23
69915

我有一个 javascript 对象,我想 递归 搜索它以查找包含特定值的任何属性。

我正在使用的 javascript 已被最小化,并且不太容易追踪。

背景

我正在使用 Bing Maps AJAX SDK。它能够添加其他图块层。每个图块层都有一个图块源对象,它指定图块 URL 的 URI 格式。

我遇到了一个问题,即图块源 URI 只创建一次,然后被缓存。因此我无法针对每个请求动态更改 URL 的参数(例如,根据一天中的时间更改图块叠加层的颜色)。

请注意,此行为与 Google 的 Map API 和适用于 WP7 的 Bing Maps API 不同,这两个 API 都允许您为每个图块请求动态创建 URL。

查找缓存的 URI,替换两个特定参数,然后使用 URI 来获取图块。

由于这是 javascript,我想找到缓存的 URI,并用一个函数替换它,该函数动态构建 URI 并返回它。

我不需要每次运行时都这样做,只是想知道属性被缓存在哪里,所以我可以编写代码来对其进行 hax0r。

原始问题

如果我将 URI 设置为某个值(如“floobieblaster”),当我设置断点时,我可以递归搜索 javascript 对象以查找“floobieblaster”并获取存储该值的属性吗?

编辑以添加

我正在搜索的对象似乎有一个循环引用,因此任何递归代码都可能导致 stackoverflow。

有什么编辑器/调试器技巧可以利用吗?

3个回答

类似这样的简单操作应该可以工作:

var testObj = {
    test: 'testValue',
    test1: 'testValue1',
    test2: {
        test2a: 'testValue',
        test2b: 'testValue1'
    }
}

function searchObj (obj, query) {

    for (var key in obj) {
        var value = obj[key];

        if (typeof value === 'object') {
            searchObj(value, query);
        }

        if (value === query) {
            console.log('property=' + key + ' value=' + value);
        }

    }

}

如果您执行 searchObj(testObj, 'testValue'); ,它将在控制台中记录以下内容:

property=test value=testValue
property=test2a value=testValue

显然,您可以用任何您想要的内容替换 console.log ,或者向 searchObj 函数添加回调参数以使其更具可重用性。

编辑: 添加了 query 参数,该参数允许您在调用该函数时指定要搜索的值。

Bryan Downing
2012-02-23

此函数将在对象中搜索。它将搜索查询与对象的每个属性进行匹配。当您需要在多维对象中搜索时,这很有用 经过几个小时的努力,我从 Google 的 AngularJS 项目获得了此代码。

/* Seach in Object */

var comparator = function(obj, text) {
if (obj && text && typeof obj === 'object' && typeof text === 'object') {
    for (var objKey in obj) {
        if (objKey.charAt(0) !== '$' && hasOwnProperty.call(obj, objKey) &&
                comparator(obj[objKey], text[objKey])) {
            return true;
        }
    }
    return false;
}
text = ('' + text).toLowerCase();
return ('' + obj).toLowerCase().indexOf(text) > -1;
};

var search = function(obj, text) {
if (typeof text == 'string' && text.charAt(0) === '!') {
    return !search(obj, text.substr(1));
}
switch (typeof obj) {
    case "boolean":
    case "number":
    case "string":
        return comparator(obj, text);
    case "object":
        switch (typeof text) {
            case "object":
                return comparator(obj, text);
            default:
                for (var objKey in obj) {
                    if (objKey.charAt(0) !== '$' && search(obj[objKey], text)) {
                        return true;
                    }
                }
                break;
        }
        return false;
    case "array":
        for (var i = 0; i < obj.length; i++) {
            if (search(obj[i], text)) {
                return true;
            }
        }
        return false;
    default:
        return false;
}
};
Hardik Sondagar
2014-07-18

以下是针对这个老问题的一些现代解决方案。您可以扩展它以满足自己的需求。假设数据结构如下:

table = {
  row1: {
    col1: 'A',
    col2: 'B',
    col3: 'C'
  },
  row2: {
    col1: 'D',
    col2: 'A',
    col3: 'F'
  },
  row3: {
    col1: 'E',
    col2: 'G',
    col3: 'C'
  }
};

获取属性 col3 等于“C”的对象的键数组:

Object.keys(table).filter(function(row) {
  return table[row].col3==='C';
});

这将返回 ['row1', 'row3']

获取属性 col3 等于“C”的行的新对象:

Object.keys(table).reduce(function(accumulator, currentValue) {
  if (table[currentValue].col3==='C') accumulator[currentValue] = table[currentValue];
  return accumulator;
}, {});

这将返回

{
  row1: {
    col1: 'A',
    col2: 'B',
    col3: 'C'
  },
  row3: {
    col1: 'E',
    col2: 'G',
    col3: 'C'
  }
}

请注意,以上答案来自 类似问题

thdoan
2018-04-26