【问题标题】:Flatten array with objects into 1 object将包含对象的数组展平为 1 个对象
【发布时间】:2015-09-17 03:22:40
【问题描述】:

给定输入:

[{ a: 1 }, { b: 2 }, { c: 3 }]

如何退货:

{ a: 1, b: 2, c: 3 }

对于带有 lodash 的数组 it's not a problem,但这里我们有对象数组。

【问题讨论】:

  • 可以在 SO 上询问 npm 包吗?
  • 没有。您可以像刚才那样描述您遇到的问题,如果答案恰好是“安装此 npm 包”,那很好;但你不应该专门要求一个包来解决问题。

标签: javascript lodash flatten


【解决方案1】:

使用Object.assign:

let merged = Object.assign(...arr); // ES6 (2015) syntax

var merged = Object.assign.apply(Object, arr); // ES5 syntax

请注意,Object.assign 尚未在许多环境中实现,您可能需要对其进行 polyfill(使用 core-js、另一个 polyfill 或使用 MDN 上的 polyfill)。

您提到了 lodash,因此值得指出的是,它带有一个 _.assign 函数,用于此目的,它做同样的事情:

 var merged = _.assign.apply(_, [{ a: 1 }, { b: 2 }, { c: 3 }]);

但我真的推荐新的标准库方式。

【讨论】:

  • 你不应该Object.assign({}, ...arr)吗?!
  • @Bergi 如果我想完整地保留assign 的输入,我可以。如果我不这样做,我当然不必。因为这不是一个要求,所以我没有这样对待它。
  • @BenjaminGruenbaum:是的,保留输入是一种最佳做法 :-) 它可能会在意外时导致丑陋的错误。
  • 如果我没有添加额外的 {},我的 linter 会抛出 Expected at least 1 arguments, but got 0 or more.Object.assign({}, ...ids.
【解决方案2】:

这是一个不使用 ES6 方法的版本...

var arr = [{ a: 1 }, { b: 2 }, { c: 3 }];
var obj = {};

for(var i = 0; i < arr.length; i++) {
    var o = arr[i];
    for(var key in o) {
        if(typeof o[key] != 'function'){
            obj[key] = o[key];
        }
    }
}

console.log(obj);

小提琴:http://jsfiddle.net/yaw3wbb8/

【讨论】:

  • 请注意,这也会复制可枚举的原型属性(在这种特殊情况下这不是问题)。
  • 是否可以在 if 语句中添加一个简单的 `&& !o.propertyIsEnumerable(key)` 来解决这个问题?
  • 好吧,for... in 仅枚举可枚举的属性。 Object(o).hasOwnProperty(obj) 会修复它(确保它不在原型上) - Object(o) 部分是为了确保我们没有调用不存在的方法,例如传递 4 不会失败(并且不复制任何内容)。
  • 可枚举的属性不是您想要复制的吗?例如,您不希望对象中有类似Array.prototype.length 的东西.. 对吗?还是我完全错过了这个?
  • @BenjaminGruenbaum:更好的是:Object.prototype.hasOwnProperty.call(o, i) 以确保我们不会调用自定义方法甚至非函数属性值。
【解决方案3】:

你可以像这样使用 underscore.extend 函数:

var _ = require('underscore');
var a = [{ a: 1 }, { b: 2 }, { c: 3 }];

var result = _.extend.apply(null, a);
console.log(result); // { a: 1, b: 2, c: 3 }
console.log(a); // [ { a: 1, b: 2, c: 3 }, { b: 2 }, { c: 3 } ]

为了防止修改原始数组,您应该使用

var _ = require('underscore');
var a = [{ a: 1 }, { b: 2 }, { c: 3 }];

var result = _.extend.apply(null, [{}].concat(a));
console.log(result); // { a: 1, b: 2, c: 3 }
console.log(a); // [ { a: 1 }, { b: 2 }, { c: 3 } ]

Here can test it

【讨论】:

    【解决方案4】:

    我有一个不需要 polyfill 的简洁小解决方案。

    var arr = [{ a: 1 }, { b: 2 }, { c: 3 }];
    var object = {};
    
    arr.map(function(obj){
        var prop = Object.getOwnPropertyNames(obj);
        object[prop] = obj[prop];
    });
    

    希望有帮助:)

    【讨论】:

    • 我不知道为什么这被赞成,因为它不能不起作用 - getOwnPropertyNames 返回一个数组。
    • 这只是偶然的,因为所有对象都有一个属性,toString使用单个属性的数组给出相同的结果,尝试向其中一个对象添加属性并看到它失败: jsfiddle.net/zqvhceyj
    • @BenjaminGruenbaum 我完全理解 - 我只是将解决方案应用于用例。我可以更笼统,但问题明确要求“对于 this 输入,返回 this 输出”,我只是这样做。
    • @JonathanBrooks 这正是我所要求的。 :-)
    • @Ultra 哈哈!这就是我从你的问题中收集到的;我很高兴我的反对票是没有根据的:')
    【解决方案5】:

    有了lodash,你可以使用merge():

    var arr = [ { a: 1 }, { b: 2 }, { c: 3 } ];
    _.merge.apply(null, [{}].concat(arr));
    // → { a: 1, b: 2, c: 3 }
    

    如果您在多个地方这样做,您可以使用partial()spread() 使merge() 更加优雅:

    var merge = _.spread(_.partial(_.merge, {}));
    merge(arr);
    // → { a: 1, b: 2, c: 3 }
    

    【讨论】:

      【解决方案6】:

      这是Object.assignarray.prototype.reduce 函数的一个很好的用法:

      let merged = arrOfObjs.reduce((accum, val) => {
        Object.assign(accum, val);
        return accum;
      }, {})
      

      这种方法不会改变输入的对象数组,这可以帮助您避免难以解决的问题。

      【讨论】:

      • 在转换为其他类型的对象时很有用
      【解决方案7】:

      您可以轻松地将对象扁平化为数组。

      function flatten(elements) {
        return elements.reduce((result, current) => {
          return result.concat(Array.isArray(current) ? flatten(current) : current);
        }, []);
      };
      

      【讨论】:

        【解决方案8】:

        除了已接受的答案之外,还有一个运行 ES6 的代码 sn-p。

        let input = [{ a: 1 }, { b: 2 }, { c: 3 }]
        //Get input object list with spread operator
        console.log(...input)
        //Get all elements in one object
        console.log(Object.assign(...input))

        【讨论】:

          【解决方案9】:

          在提出这个问题 6 年后。

          Object.assign 是我最喜欢的答案(上图)。

          但这也合法吗?

          let res = {};
          [{ a: 1 }, { b: 2 }, { c: 3 }].forEach(val => {
              let key = Object.keys(val);
              console.log(key[0]);
              res[key] = val[key];
          })
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 2014-03-01
            • 1970-01-01
            • 2020-11-15
            • 1970-01-01
            • 1970-01-01
            • 2016-12-06
            • 2015-09-03
            相关资源
            最近更新 更多