Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/jquery/71.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript 在深层对象中按名称查找属性_Javascript_Jquery_Lodash - Fatal编程技术网

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

Javascript 在深层对象中按名称查找属性,javascript,jquery,lodash,Javascript,Jquery,Lodash,我有一个庞大的收集,我正在寻找一个关键的财产内的某个地方收集。获取包含该键/索引的所有对象的引用列表或完整路径的可靠方法是什么?如果有帮助的话,我使用jQuery和lodash,您可以忘记无限指针递归,这是一个纯JSON响应 fn({ 'a': 1, 'b': 2, 'c': {'d':{'e':7}}}, "d"); // [o.c] fn({ 'a': 1, 'b': 2, 'c': {'d':{'e':7}}}, "e"); // [o.c.d] fn({ 'aa': 1, 'bb'

我有一个庞大的收集,我正在寻找一个关键的财产内的某个地方收集。获取包含该键/索引的所有对象的引用列表或完整路径的可靠方法是什么?如果有帮助的话,我使用jQuery和lodash,您可以忘记无限指针递归,这是一个纯JSON响应

fn({ 'a': 1, 'b': 2, 'c': {'d':{'e':7}}}, "d"); 
// [o.c]

fn({ 'a': 1, 'b': 2, 'c': {'d':{'e':7}}}, "e");
// [o.c.d]

fn({ 'aa': 1, 'bb': 2, 'cc': {'d':{'x':9}}, dd:{'d':{'y':9}}}, 'd');
// [o.cc,o.cc.dd]

fwiw-lodash有一个u.find函数,该函数将查找两个嵌套深度的嵌套对象,但之后它似乎失败了。(例如)

类似的东西可以工作,将其转换为对象并向下递归

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

Fiddle:

纯JavaScript解决方案如下所示:

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;
}
以下是如何使用此功能:

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

[{x: 9}, {y: 9}]
这应该做到:

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

这将深入搜索对象数组(hay)中的值(指针),然后返回一个包含结果的数组

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;
}
我是这样做的:

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 );
            }
        }
    }
}
使用以下工具进行测试:

var obj = {
    document: {
        payload: {
            items:[
                {field1: 123},
                {field1: 456}
                ]
        }
    }
};
var results = [];

_find(obj.document,'payload.items.field1', results);
console.log(results);
输出

[ 123, 456 ]

如果您可以用纯JS(或与lodash的组合)编写递归函数,这将是最好的(根据性能),但是如果您希望跳过递归,并希望使用简单可读的代码(根据性能可能不是最好的),那么您可以将其用于任何需要递归遍历对象的目的

let findValuesDeepByKey = (obj, key, res = []) => (
    _.cloneDeepWith(obj, (v,k) => {k==key && res.push(v)}) && res
)
因此,您作为
\uu1.cloneDeepWith
的第二个参数传递的回调将递归地遍历所有
键/值
对,您所要做的就是对每个键/值进行操作。上面的代码只是您案例的一个示例。以下是一个工作示例:

var对象={
提案1:‘ABC1’,
方案二:“ABC2”,
提案3:{
方案4:‘ABC3’,
prop5Arr:[{
prop5:'XYZ'
},
{
方案五:“ABC4”
},
{
建议6:{
prop6NestedArr:[{
prop1:'XYZ嵌套Arr'
},
{
属性:{key100:'100 Value'}
}
]
}
}
]
}
}
让FindValuesDepByKey=(对象、键、结果=[])=>(
_.cloneDeepWith(obj,(v,k)=>{k==键和res.push(v)})和res
)
log(findValuesDepByKey(对象“prop1”);
log(findValuesDepbyKey(对象“prop5”);
log(findValuesDepbyKey(对象“key100”)
使用Deepdash,您可以从中获取,或者(构建路径->值对象)


这里有一个

如果你看不到@eugene的更新答案,这个调整允许传递一个要搜索的键列表

// Method that will find any "message" in the Apex errors that come back after insert attempts
// Could be a validation rule, or duplicate record, or pagemessage.. who knows!
// Use in your next error toast from a wire or imperative catch path!   
// message: JSON.stringify(this.findNested(error, ['message', 'stackTrace'])),
// Testing multiple keys: this.findNested({thing: 0, list: [{message: 'm'}, {stackTrace: 'st'}], message: 'm2'}, ['message', 'stackTrace'])
findNested(obj, keys, memo) {
    let 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 (keys.includes(i)) {
          memo.push(obj[i]);
        } else if ('[object Array]' === ts.call(obj[i]) || '[object Object]' === ts.call(obj[i])) {
          this.findNested(obj[i], keys, memo);
        }
      }
    }
  
    return memo.length == 0 ? null : memo;
}
我们用于数据处理任务。一旦你掌握了如何使用它,它就非常棒了

//const objectScan=require('object-scan');
常量haystack={a:{b:{c:'d'},e:{f:'g'};
const r=objectScan(['a.*.]],{joined:true,rtn:'entry'})(haystack);
控制台日志(r);
//=>
。作为控制台包装{最大高度:100%!重要;顶部:0}

这几乎对我有效。我不得不将第3行更改为
return[obj[key],这样我就可以得到一个键值数组,而不是包装object@ChrisMontgomery:是的,但OP想要“包含该键的所有对象”(可能他正在对结果执行
pull()
)@Bergi是有道理的。您的解决方案适用于我的所有场景,而Al-Jey的答案在对象中的数组中的对象存在问题。
res.push(v)
res.push.apply(res,v)之间有什么区别
?@MichaelTrouw:实际上,如果满足
if
条件,则
v
始终是一个数组,因为
fn
始终返回一个数组。我们在这里使用
push.apply
将多个项一次附加到
res
数组中,就像
res=res.concat(v)
那样,但不创建新数组。此解决方案不适用于嵌套数组,例如
findNested({'a':[{'b':{'c':7}},'b')
而@Bergidoes@ChrisMontgomery,这是因为最初的问题只包括对象,没有任何数组,我已经更新了示例。@AlJey,对于你的lodash示例,我使用了
var o={a:{really:'long'},obj:{that:{keeps:{keeps:'going'}}}
然后
findNested(o,'that')
,这给了我
范围错误:超过了最大调用堆栈大小
。第一个工程辉煌虽然!Uncaught RangeError:最大调用堆栈大小超出了Di在上使用它的大小window@ryanyuyu-可读,不接近缩小。这是通俗易懂的英语,但确实需要相当多的智商才能理解。这是一个美丽而复杂的解决方案,它将大脑的压力压到了极限:)@vsync代码已经被编辑过了。请参阅“您应避免使用“仅限代码”答案”。请提供有关代码的一些上下文。我在尝试搜索窗口对象上的属性时遇到了超出最大调用堆栈的错误。是否启用了循环检查选项?默认情况下是关闭的。共享您的代码,我将帮助修复它我得到了错误:
TypeError:instanceof'的右边不是一个对象
我没有用于测试的Netscape浏览器,但这在chrome中是有效的:
(function(){var ld=window.;window.=null;var cherry=ld.pickDeep(window,'Netscape',{checkCircular:true});console.log({cherry});})当deepdash试图迭代它所依赖的全局lodash对象时,会发生一些奇怪的事情,所以将其移动到某个局部范围。我得到了完全相同的错误。每次我的应用程序的本地存储也会被清除,这很奇怪。我运行了以下命令:
(function(){var-ld=u;deepdash(ld);u=null;var-cherry=ld.pickDee
var obj = { 'aa': 1, 'bb': 2, 'cc': {'d':{'x':9}}, dd:{'d':{'y':9}}}

var cherry = _.pickDeep(obj,"d");

console.log(JSON.stringify(cherry));
// {"cc":{"d":{}},"dd":{"d":{}}}

var paths = _.paths(cherry);

console.log(paths);
// ["cc.d", "dd.d"]

paths = _.paths(cherry,{pathFormat:'array'});

console.log(JSON.stringify(paths));
// [["cc","d"],["dd","d"]]

var index = _.indexate(cherry);

console.log(JSON.stringify(index));
// {"cc.d":{},"dd.d":{}}
// Method that will find any "message" in the Apex errors that come back after insert attempts
// Could be a validation rule, or duplicate record, or pagemessage.. who knows!
// Use in your next error toast from a wire or imperative catch path!   
// message: JSON.stringify(this.findNested(error, ['message', 'stackTrace'])),
// Testing multiple keys: this.findNested({thing: 0, list: [{message: 'm'}, {stackTrace: 'st'}], message: 'm2'}, ['message', 'stackTrace'])
findNested(obj, keys, memo) {
    let 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 (keys.includes(i)) {
          memo.push(obj[i]);
        } else if ('[object Array]' === ts.call(obj[i]) || '[object Object]' === ts.call(obj[i])) {
          this.findNested(obj[i], keys, memo);
        }
      }
    }
  
    return memo.length == 0 ? null : memo;
}