在深层对象中按名称查找属性

我有一个巨大的集合,我正在寻找一个属性收集内的关键某处。 获取包含该键/索引的所有对象的引用列表或完整path的可靠方法是什么? 我使用jQuery和lodash,如果它有帮助,你可以忘记无限指针recursion,这是一个纯粹的JSON响应。

fn({ 'a': 1, 'b': 2, 'c': {'d':{'e':7}}}, "d"); // [oc] fn({ 'a': 1, 'b': 2, 'c': {'d':{'e':7}}}, "e"); // [ocd] fn({ 'aa': 1, 'bb': 2, 'cc': {'d':{'x':9}}, dd:{'d':{'y':9}}}, 'd'); // [o.cc,o.cc.dd] 

fwiw lodash有一个_.find函数,它可以find两个嵌套深的嵌套对象,但似乎在这之后失败了。 (例如http://codepen.io/anon/pen/bnqyh )

这应该做到这一点:

 function fn(obj, key) { if (_.has(obj, key)) // or just (key in obj) return [obj]; // elegant: return _.flatten(_.map(obj, function(v) { return typeof v == "object" ? fn(v, key) : []; }), true); // or efficient: var res = []; _.forEach(obj, function(v) { if (typeof v == "object" && (v = fn(v, key)).length) res.push.apply(res, v); }); return res; } 

一个纯粹的JavaScript解决scheme将如下所示:

 function findNested(obj, key, memo) { var i, proto = Object.prototype, ts = proto.toString, hasOwn = proto.hasOwnProperty.bind(obj); if ('[object Array]' !== ts.call(memo)) memo = []; for (i in obj) { if (hasOwn(i)) { if (i === key) { memo.push(obj[i]); } else if ('[object Array]' === ts.call(obj[i]) || '[object Object]' === ts.call(obj[i])) { findNested(obj[i], key, memo); } } } return memo; } 

这里是你如何使用这个function:

 findNested({'aa': 1, 'bb': 2, 'cc': {'d':{'x':9}}, dd:{'d':{'y':9}}}, 'd'); 

其结果是:

 [{x: 9}, {y: 9}] 

这将深入search对象(干草)的数组(针),然后返回一个数组结果…

 search = function(hay, needle, accumulator) { var accumulator = accumulator || []; if (typeof hay == 'object') { for (var i in hay) { search(hay[i], needle, accumulator) == true ? accumulator.push(hay) : 1; } } return new RegExp(needle).test(hay) || accumulator; } 

像这样的东西会工作,将其转换为一个对象,并recursion下来。

 function find(jsonStr, searchkey) { var jsObj = JSON.parse(jsonStr); var set = []; function fn(obj, key, path) { for (var prop in obj) { if (prop === key) { set.push(path + "." + prop); } if (obj[prop]) { fn(obj[prop], key, path + "." + prop); } } return set; } fn(jsObj, searchkey, "o"); } 

小提琴: jsfiddle

 Array.prototype.findpath = function(item,path) { return this.find(function(f){return item==eval('f.'+path)}); } 

以下是我如何做到的:

 function _find( obj, field, results ) { var tokens = field.split( '.' ); // if this is an array, recursively call for each row in the array if( obj instanceof Array ) { obj.forEach( function( row ) { _find( row, field, results ); } ); } else { // if obj contains the field if( obj[ tokens[ 0 ] ] !== undefined ) { // if we're at the end of the dot path if( tokens.length === 1 ) { results.push( obj[ tokens[ 0 ] ] ); } else { // keep going down the dot path _find( obj[ tokens[ 0 ] ], field.substr( field.indexOf( '.' ) + 1 ), results ); } } } } 

testing它:

 var obj = { document: { payload: { items:[ {field1: 123}, {field1: 456} ] } } }; var results = []; _find(obj.document,'payload.items.field1', results); console.log(results); 

输出

 [ 123, 456 ]