将包含对象的数组展平为 1 个对象
Posted
技术标签:
【中文标题】将包含对象的数组展平为 1 个对象【英文标题】:Flatten array with objects into 1 object 【发布时间】: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 包”,那很好;但你不应该专门要求一个包来解决问题。 【参考方案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 输出”,我只是这样做。
@Jonathan***s 这正是我所要求的。 :-)
@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.assign
与array.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];
)
【讨论】:
以上是关于将包含对象的数组展平为 1 个对象的主要内容,如果未能解决你的问题,请参考以下文章