【问题标题】:How to loop javascript object of objects and find a property如何循环对象的javascript对象并找到属性
【发布时间】:2015-02-27 15:03:00
【问题描述】:

我有一个示例对象:

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

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

【问题讨论】:

    标签: javascript loops recursion


    【解决方案1】:

    自从最初回答这个问题以来,我受到启发,开始开发一个图书馆来做到这一点: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"));
    

    【讨论】:

      【解决方案2】:

      您必须对要检查的内容有一个正确的认识。 IE。对象层次结构的路径。因为如果你刚开始递归地迭代所有属性(键),一开始它的效率并不高,而且很有可能进入循环引用。

      尽管如此,您可以查询对象属性,以及向下层级的属性属性:

      /**
       * 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'));
      

      【讨论】:

        【解决方案3】:

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

        How do I check if an object has a property in JavaScript?

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

        【讨论】:

          【解决方案4】:

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

          /**
              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 以添加到子属性对象。这个_parent 将是一个包含完整子属性路径的字符串。在传递给回调函数之前,它会在每次递归时更新。然后,可以返回 _path 而不是 true 条件。

          【讨论】:

            猜你喜欢
            • 2012-10-03
            • 1970-01-01
            • 2017-06-11
            • 1970-01-01
            • 2016-04-13
            • 1970-01-01
            • 2021-11-20
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多