繁体   English   中英

如何循环对象的javascript object并找到一个属性

[英]How to loop javascript object of objects and find a property

我有一个样本 object:

var test = {obj: check, oi: "5"  }        
var lord = {sol: "5"};
var holand = {vol: "try", mice: lord}
var second = {bol: "true"};
var check = { fol: holand}

我的问题是如何检索 object“测试”是否具有“溶胶”属性,该属性位于另一个 object 几层深处。 它应该是一个有点递归的 function 吗? 如果 function 返回 true(属性存在),是否可以检索属性的某种路径。 在这种情况下,路径应该是 test["obj"]["fol"]["mice"]

自从最初回答这个问题以来,我受到启发去在图书馆工作以做到这一点: koalaesce

它的工作原理类似于:

 var test = { obj: check, oi: "5" } var lord = { sol: "5" }; var holand = { vol: "try", mice: lord } var second = { bol: "true" }; var check = { fol: holand } function getDescendent(base, steps) { var step = base; for (var i = 0; i < steps.length; ++i) { if (step.hasOwnProperty(steps[i])) { step = step[steps[i]]; } else { throw new Error("Missing link at " + steps[i]); } } return step; } document.write(getDescendent(check, ["fol", "mice", "sol"])); try { document.write(getDescendent(check, ["fol", "tofu", "sol"])); } catch (e) { document.write(e); } 

此处的算法从base对象开始,一直向下进行,遍历代表每个步骤的属性名称的字符串数组。 它检查以确保当前对象具有其自己的属性( 不是继承的属性)并具有适当的名称,然后向下移动到该级别。 如果对象不存在,则会抛出缺少的名称。

在很多情况下,您可能希望删除hasOwnProperty检查,因为继承/原型属性和方法可能很有用(并且不会造成任何伤害)。 在您的情况下,使用简单的对象,行为不会改变。 在大多数情况下, 检查将允许您访问更多属性。

对于更聪明的ES6解决方案,您还可以使用reduce和:

let test = {
  obj: check,
  oi: "5"
}
let lord = {
  sol: "5"
};
let holand = {
  vol: "try",
  mice: lord
}
let second = {
  bol: "true"
};
let check = {
  fol: holand
}

function getDescendent(base, ...steps) {
  return steps.reduce((prev, cur) => {
    if (prev && prev.hasOwnProperty(cur)) {
      return prev[cur];
    } else {
      throw new Error("Missing link at " + cur);
    }
  }, base);
}

document.write(getDescendent(check, "fol", "mice", "sol"));
document.write(getDescendent(check, "fol", "tofu", "sol"));

您可以通过检查对象的属性来进行递归循环。 此线程描述如何检查该属性是否存在。

如何检查对象在JavaScript中是否具有属性?

是的,如果您想知道路径,则在递归时必须保持跟踪。

您必须有一个正确的想法要检查什么。 即沿着对象层次结构的路径。 因为如果您刚开始递归地迭代所有属性(键),那么它一开始就没有效率,并且很有可能进入循环引用。

不过,您可以查询对象属性,以及属性的属性。

/**
 * Get a property defined under given object's hierarchy, matching given path.
 * @param obj Object to look into.
 * @param path filesystem style path for properties. E.g '/prop1/prop2/prop3'
 * @returns {*} Property under object hierarchy, or undefined.
 */
function getProp(obj,path){
    var props = path.split('/').reverse();
    var p;
    var o = obj;
    while( p = props.pop()){
        o = o[p]; // you can use your preferred scope. i.e own property only
        if(o == undefined){
            return o;
        }
    }

    return o;
}

/**
 * Utility function to check if a property is defined under given object's hierarchy, matching given path.
 * @param obj Object to look into.
 * @param path filesystem style path for properties. E.g '/prop1/prop2/prop3'
 * @returns {boolean} true if property is defined, false if property is undefined.
 */
function hasProp(obj, path){
    return getProp(obj,path) != undefined;
}


// Test object
var testObj = {
                a:{
                    b:{
                        c:'hello',
                        d:{
                            e:'world'
                        }
                    }
                }
              };

// valid property paths
console.log(hasProp(testObj,'a/b/c/'));
console.log(hasProp(testObj,'a/b/d/e'));
console.log(getProp(testObj,'a/b/c/'));
console.log(getProp(testObj,'a/b/d/e'));

// invalid property paths
console.log(hasProp(testObj,'a/d/c/'));
console.log(hasProp(testObj,'a/b/d/e/f'));
console.log(getProp(testObj,'a/d/c/'));
console.log(getProp(testObj,'a/b/d/e/f'));

这是一种(大部分)纯函数式方法,可以使用某种“条件”进行递归:

/**
    Recurse through object until condition is met.
    @param {Array} objs An array of objects
    @return {Boolean} Whether condition is met.
*/
const recurseObjs = (objs, condition) => {
    const _subObjs = []
    for (let obj of objs) {
        for (let val of Object.values(obj)) {
            if (val === condition /*replace with some condition or multiple*/) return true // Stop if your condition is found
            else if (typeof val === 'object' && val !== null && Object.prototype.toString.call(val) !== '[object Array]') _subObjs.push(val) // Else recurse through subobjects that are not array or null
        }
    }
    if (_subObjs.length > 0) return recurseObjs(_subObjs, condition); 
    return false // Default return value if condition not found
}

recurseObjs([{foo:'bar'},{hello:{cruel:'world'}}],'world') // => true
recurseObjs([{foo:'bar'},{hello:{cruel:'world'}}],'test') // => false

如果需要对象的“已找到”子属性值的完整路径,您可以创建一个新键值_parent以添加到子属性 object。此_parent将是一个包含完整子属性路径的字符串。 在传递给回调 function 之前,它会在每次递归时更新。然后,可以返回_path而不是true条件。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM