我有一个javascript对象,我想递归搜索它以查找包含特定值的任何属性。
我正在使用的javascript已经缩小,并且不容易追踪。
背景
我正在使用Bing Maps AJAX SDK。它可以添加其他图块层。每个tilelayer都有一个tilesource对象,它指定了tile URL的URI格式。
我遇到了一个问题,即一次创建tilesource URI并缓存。因此,我无法动态更改每个请求的URL参数(例如,根据一天中的时间更改图块叠加层的颜色)。
请注意,此行为与Google的Map API和WP7的Bing Maps API不同,后者允许您为每个磁贴请求动态创建URL。
查找缓存的URI,并替换两个特定参数,然后使用URI获取磁贴。
由于这是javascript,我想找到缓存的URI,并用一个函数替换它,而不是动态构建URI,然后返回它。
我不需要每个运行时都这样做,只是想要和想法缓存属性的位置,所以我可以编写代码给hax0r它。
原始问题
如果我将URI设置为某个值,如“floobieblaster”,当我设置断点时,我可以递归搜索javascript对象的“floobieblaster”并获取存储该值的属性吗?
编辑以添加
我正在搜索的对象似乎有一个循环引用,因此任何递归代码都可能导致堆栈溢出。
我可以使用任何编辑器/调试器技巧吗?
答案 0 :(得分:22)
像这样简单的东西应该有效:
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
参数,可让您在调用函数时指定要搜索的值。
答案 1 :(得分:2)
这是我的解决方案,它使用正则表达式测试匹配给定的字符串/值并返回匹配的数组。这不是递归的,但是你已经从你的问题中删除了这个。
这是我在以下主题中的回答: Search a JavaScript object
与其他人建议的相同的原则 - 搜索对象的特定值,对于任何寻找此解决方案的人来说。
功能:
Array.prototype.findValue = function(name, value){
var array = $.map(this, function(v,i){
var haystack = v[name];
var needle = new RegExp(value);
// check for string in haystack
// return the matched item if true, or null otherwise
return needle.test(haystack) ? v : null;
});
return this;
}
你的对象:
myObject = {
name : "soccer",
elems : [
{name : "FC Barcelona"},
{name : "Liverpool FC"}
]
},
{
name : "basketball",
elems : [
{name : "Dallas Mavericks"}
]
}
用法:
(这将在myObject.elems数组中搜索' name'匹配' FC')
var matched = myObject.elems.findValue('name', 'FC');
console.log(matched);
结果 - 检查你的控制台:
[Object, Object, keepMatching: function, findValue: function]
0: Object
name: "FC Barcelona"
__proto__: Object
1: Object
name: "Liverpool FC"
__proto__: Object
length: 2
__proto__: Array[0]
如果您想要完全匹配,只需将三元语句中的正则表达式更改为基本值匹配即可。 即。
v[name] === value ? v : null
答案 2 :(得分:2)
此功能将在对象中搜索。它将Search Query与Object的每个属性匹配。当您需要在多维对象中进行搜索时,这非常有用 花了几个小时后,我从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;
}
};
答案 3 :(得分:1)
这是一种基于Bryan方法的更方便的随时可用的静态方法:
/**
* Find properties matching the value down the object tree-structure.
* Ignores prototype structure and escapes endless cyclic nesting of
* objects in one another.
*
* @param {Object} object Object possibly containing the value.
* @param {String} value Value to search for.
* @returns {Array<String>} Property paths where the value is found.
*/
getPropertyByValue: function (object, value) {
var valuePaths;
var visitedObjects = [];
function collectValuePaths(object, value, path, matchings) {
for (var property in object) {
if (
visitedObjects.indexOf(object) < 0 &&
typeof object[property] === 'object') {
// Down one level:
visitedObjects.push(
object);
path =
path +
property + ".";
collectValuePaths(
object[property],
value,
path,
matchings);
}
if (object[property] === value) {
// Matching found:
matchings.push(
path +
property);
}
path = "";
}
return matchings;
}
valuePaths =
collectValuePaths(
object,
value,
"",
[]);
return valuePaths;
}
对象
var testObj = {
test: 'testValue',
test1: 'testValue1',
test2: {
test2a: 'testValue',
test2b: 'testValue1'
}
}
将导致
["test", "test2.test2a"]
答案 4 :(得分:0)
我编辑了Bryan Downing的答案,打印深层对象的层次结构:
function searchObj (obj, query, prefix /*not to be set*/) {
prefix = prefix || "---";
var printKey;
for (var key in obj) {
var value = obj[key];
if (typeof value === 'object') {
if (searchObj(value, query, prefix + "|---")) {
console.log(prefix + ' ' + key);
printKey = true;
}
}
if (value === query) {
console.log(prefix + ' ' + key + ' = ' + value);
return true;
}
}
return printKey;
}
然后,运行searchObj(testObj, 'testValue');
答案 5 :(得分:0)
以下是这个老问题的一些现代解决方案。您可以扩展它以满足您自己的需要。假设以下数据结构:
table = {
row1: {
col1: 'A',
col2: 'B',
col3: 'C'
},
row2: {
col1: 'D',
col2: 'A',
col3: 'F'
},
row3: {
col1: 'E',
col2: 'G',
col3: 'C'
}
};
获取属性col3
等于&#34; C&#34;
Object.keys(table).filter(function(row) {
return table[row].col3==='C';
});
这将返回['row1', 'row3']
。
获取属性col3
等于&#34; C&#34;
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'
}
}
请注意,上述答案来自similar question。