【问题标题】:how to convert this nested object into a flat object?如何将此嵌套对象转换为平面对象?
【发布时间】:2016-04-03 12:13:44
【问题描述】:

抱歉,我不知道如何表达问题标题。如果可能,请帮助编辑。

我有一个这样的对象:

{
    a: 'jack',
    b: {
        c: 'sparrow',
        d: {
           e: 'hahaha'
        }
    }
}

我想让它看起来像:

{
    'a': 'jack',
    'b.c': 'sparrow',
    'b.d.e': 'hahaha'
}

// so that I can use it this way:
a['b.d.e']

jQuery 也可以。我知道对于嵌套对象,我可以使用a.b.d.e 来获取hahaha,但是今天我必须像a['b.d.e'] 一样使用它-_-!!! 我怎样才能做到这一点?在此先感谢:)

【问题讨论】:

    标签: javascript jquery


    【解决方案1】:

    您可以使用递归函数来抓取对象并将其展平。

    var test = {
        a: 'jack',
        b: {
            c: 'sparrow',
            d: {
                e: 'hahaha'
            }
        }
    };
    
    function traverseAndFlatten(currentNode, target, flattenedKey) {
        for (var key in currentNode) {
            if (currentNode.hasOwnProperty(key)) {
                var newKey;
                if (flattenedKey === undefined) {
                    newKey = key;
                } else {
                    newKey = flattenedKey + '.' + key;
                }
    
                var value = currentNode[key];
                if (typeof value === "object") {
                    traverseAndFlatten(value, target, newKey);
                } else {
                    target[newKey] = value;
                }
            }
        }
    }
    
    function flatten(obj) {
        var flattenedObject = {};
        traverseAndFlatten(obj, flattenedObject);
        return flattenedObject;
    }
    
    var flattened = JSON.stringify(flatten(test));
    console.log(flattened);

    【讨论】:

      【解决方案2】:

      另一种递归实现。 我只是想自己编写一个实现,尽管当前的实现已经非常好。

      递归函数检查键是否为'object'类型。

      • 如果是对象,我们会按每个对象的键进行迭代。
      • 否则,我们将其添加到我们的结果对象中。
      function flat(res, key, val, pre = '') {
        const prefix = [pre, key].filter(v => v).join('.');
        return typeof val === 'object'
          ? Object.keys(val).reduce((prev, curr) => flat(prev, curr, val[curr], prefix), res)
          : Object.assign(res, { [prefix]: val});
      }
      return Object.keys(input).reduce((prev, curr) => flat(prev, curr, input[curr]), {});
      

      扁平化 NPM 包

      或者您可以简单地使用flat npm package,这是一个众所周知的测试库。

      var flatten = require('flat')
      flatten(obj);
      

      ⬑ 我会在严肃的代码中使用它。

      [Extra] 更简洁地调用上述函数

      function flatObject(input) {
        function flat(res, key, val, pre = '') {
          const prefix = [pre, key].filter(v => v).join('.');
          return typeof val === 'object'
            ? Object.keys(val).reduce((prev, curr) => flat(prev, curr, val[curr], prefix), res)
            : Object.assign(res, { [prefix]: val});
        }
      
        return Object.keys(input).reduce((prev, curr) => flat(prev, curr, input[curr]), {});
      }
      
      const result = flatObject(input);
      

      [额外]演示

      http://codepen.io/zurfyx/pen/VpErja?editors=1010

      function flatObject(input) {
        function flat(res, key, val, pre = '') {
          const prefix = [pre, key].filter(v => v).join('.');
          return typeof val === 'object'
            ? Object.keys(val).reduce((prev, curr) => flat(prev, curr, val[curr], prefix), res)
            : Object.assign(res, { [prefix]: val});
        }
      
        return Object.keys(input).reduce((prev, curr) => flat(prev, curr, input[curr]), {});
      }
      
      const result = flatObject({
          a: 'jack',
          b: {
              c: 'sparrow',
              d: {
                 e: 'hahaha'
              }
          }
      });
      
      document.getElementById('code').innerHTML = JSON.stringify(result, null, 2);
      <pre><code id="code"></code></pre>

      【讨论】:

        【解决方案3】:

        您可以遍历对象的entries。如果value 是一个对象,则递归调用该函数。使用flatMap 获取扁平化的条目数组。

        然后使用Object.fromEntries()从扁平化的条目数组中获取一个对象

        const input = {
          a: 'jack',
          b: {
            c: 'sparrow',
            d: {
              e: 'hahaha'
            }
          }
        }
        
        const getEntries = (o, prefix = '') => 
          Object.entries(o).flatMap(([k, v]) => 
            Object(v) === v  ? getEntries(v, `${prefix}${k}.`) : [ [`${prefix}${k}`, v] ]
          )
        
        console.log(
          Object.fromEntries(getEntries(input))
        )

        注意Object(v) === v 仅针对对象返回 truetypeof v === 'object' 也适用于 v = null

        【讨论】:

          【解决方案4】:

          选项 1:导出仅包含树叶的平面对象。即导出的对象仅包含末尾带有原始值的路径(参见示例)。

          //recursion: walk on each route until the primitive value.
          //Did we found a primitive?
          //Good, then join all keys in the current path and save it on the export object.
          export function flatObject(obj) {
              const flatObject = {};
              const path = []; // current path
          
              function dig(obj) {
                  if (obj !== Object(obj))
                      /*is primitive, end of path*/
                      return flatObject[path.join('.')] = obj; /*<- value*/ 
              
                  //no? so this is an object with keys. go deeper on each key down
                  for (let key in obj) {
                      path.push(key);
                      dig(obj[key]);
                      path.pop();
                  }
              }
          
              dig(obj);
              return flatObject;
          }
          
          

          示例

          let  obj = {aaa:{bbb:{c:1,d:7}}, bb:{vv:2}}
          console.log(flatObject(obj))
          /*
          {
            "aaa.bbb.c": 1,
            "aaa.bbb.d": 7,
            "bb.vv": 2
          }
          */
          

          选项 2:导出具有所有中间路径的平面对象。 更短更简单一些(参见示例)。

          export function flatObject(obj) {
              const flatObject = {};
              const path = []; // current path
          
              function dig(obj) {
                  for (let key in obj) {
                      path.push(key);
                      flatObject[path.join('.')] = obj[key];
                      dig(obj[key])
                      path.pop();
                  }
              }
          
              dig(obj);
              return flatObject;
          }
          

          示例

          let  obj = {aaa:{bbb:{c:1,d:7}}, bb:{vv:2}}
          console.log(flatObject(obj))
          /*{
            "aaa": {
              "bbb": {
                "c": 1,
                "d": 7
              }
            },
            "aaa.bbb": {
              "c": 1,
              "d": 7
            },
            "aaa.bbb.c": 1,
            "aaa.bbb.d": 7,
            "bb": {
              "vv": 2
            },
            "bb.vv": 2
          }
          */
          

          【讨论】:

            【解决方案5】:

            递归是这种情况的最佳解决方案。

            function flatten(input, reference, output) {
              output = output || {};
              for (var key in input) {
                var value = input[key];
                key = reference ? reference + '.' + key : key;
                if (typeof value === 'object' && value !== null) {
                  flatten(value, key, output);
                } else {
                  output[key] = value;
                }
              }
              return output;
            }
            var result = flatten({
              a: 'jack',
              b: {
                c: 'sparrow',
                d: {
                  e: 'hahaha'
                }
              }
            });
            document.body.textContent = JSON.stringify(result);

            【讨论】:

              【解决方案6】:

              使用父键参数的递归方法。

              const
                  getValues = (object, parents = []) => Object.assign({}, ...Object
                      .entries(object)
                      .map(([k, v]) => v && typeof v === 'object'
                          ? getValues(v, [...parents, k])
                          : { [[...parents, k].join('.')]: v }
                      )
                  ),
                  object = { a: 'jack', b: { c: 'sparrow', d: { e: 'hahaha' } } };
              
              console.log(getValues(object));

              【讨论】:

                【解决方案7】:

                只是一个示例,您如何使用 ES6 功能实现这一目标。

                const flatObject = obj => {
                    const keys = Object.keys(obj)
                
                    return keys.reduce((acc, k) => {
                        const value = obj[k]
                
                        return typeof value === 'object' ?
                             {...acc, ...ObjectUtils.flatObject(value)} :
                             {...acc, [k]: value}
                    } , {})
                }
                

                【讨论】:

                • ObjectUtils 是从哪里来的?
                • 我猜该行应该是{...acc, ...flatObject(value)} : - 作为递归调用
                【解决方案8】:

                另一种使用 ES6 的方法。

                const obj = {
                  a: "jack",
                  b: {
                    c: "sparrow",
                    d: {
                      e: "hahaha"
                    }
                  }
                };
                
                function flattenObj(value, currentKey) {
                  let result = {};
                
                  Object.keys(value).forEach(key => {
                
                    const tempKey = currentKey ? `${currentKey}.${key}` : key;
                
                    if (typeof value[key] !== "object") {
                      result[tempKey] = value[key];
                    } else {
                      result = { ...result, ...flattenObj(value[key], tempKey) };
                    }
                  });
                
                  return result;
                }
                
                console.log(flattenObj(obj));
                

                【讨论】:

                  【解决方案9】:

                  var flattenObject = function(ob) {
                    var toReturn = {};
                  
                    for (var i in ob) {
                      if (!ob.hasOwnProperty(i)) continue;
                  
                      if ((typeof ob[i]) == 'object' && ob[i] !== null) {
                        var flatObject = flattenObject(ob[i]);
                        for (var x in flatObject) {
                          if (!flatObject.hasOwnProperty(x)) continue;
                  
                          toReturn[i + '.' + x] = flatObject[x];
                        }
                      } else {
                        toReturn[i] = ob[i];
                      }
                    }
                    console.log(toReturn)
                    return toReturn;
                  };
                  
                  var ob = {
                    'a': {
                      'b': {
                        'b2': 2
                      },
                      'c': {
                        'c2': 2,
                        'c3': 3
                      }
                    }
                  };
                  flattenObject(ob);

                  【讨论】:

                  • 您能否编辑您的答案,以便解释您的解决方案!?谢谢。
                  【解决方案10】:
                  const flatten = function(obj) {
                    const result = {};
                  
                    for (let key in obj) {
                      if (typeof obj[key] === 'object') {
                        const childObj = flatten(obj[key]);
                      
                        for (let childObjKey in childObj) {
                          result[`${key}.${childObjKey}`] = childObj[childObjKey];
                        }
                      } else {
                        result[key] = obj[key];
                      }
                    }
                    return result
                  }
                  
                  var test = {
                      a: 'jack',
                      b: {
                          c: 'sparrow',
                          d: {
                              e: 'hahaha'
                          }
                      }
                  };
                  
                  console.log(flatten(test));
                  

                  【讨论】:

                    【解决方案11】:

                    试试这个

                    const result = [].concat.apply([], parentArray.map((item: any) =&gt; item.any)

                    【讨论】:

                    • 这不是 JavaScript,这不是关于普通对象的,它甚至不适用于数组。这段代码应该如何工作没有上下文。一般来说,“try this” answers are not useful。请添加一些解释。仅代码的答案对未来的读者不太有用,并且不能解释 OP 的错误或如何解决问题。
                    猜你喜欢
                    • 1970-01-01
                    • 2017-12-03
                    • 2020-01-15
                    • 2019-05-14
                    • 2016-11-16
                    • 1970-01-01
                    • 1970-01-01
                    • 2021-05-28
                    相关资源
                    最近更新 更多