如何将普通对象转换为 ES6 Map?
Posted
技术标签:
【中文标题】如何将普通对象转换为 ES6 Map?【英文标题】:How to convert a plain object into an ES6 Map? 【发布时间】:2016-08-07 06:24:02 【问题描述】:由于某种原因,我在MDN docs 中找不到这个简单的东西(也许我只是想念它)。
我希望这会起作用:
const map = new Map(foo: 'bar');
map.get('foo'); // 'bar'
...但第一行抛出TypeError: (var)[Symbol.iterator] is not a function
如何从普通对象制作地图?我真的必须先将其转换为键值对数组的数组吗?
【问题讨论】:
FWIW,可能值得将您接受的答案从 mine 切换到 nils' 或 bergi's。Object.entries
确实是比Object.keys
更好的方法,而bergi 的生成器函数方法比Object.keys
或Object.entries
更直接。
【参考方案1】:
ES6
将对象转换为地图:
const objToMap = (o) => new Map(Object.entries(o));
将地图转换为对象:
const mapToObj = (m) => [...m].reduce( (o,v)=> o[v[0]] = v[1]; return o; , )
注意:mapToObj 函数假定映射键是字符串(否则会失败)
【讨论】:
【参考方案2】:The answer by Nils 描述了如何 将对象转换为地图,我发现这非常有用。但是,OP 也想知道这些信息在 MDN 文档中的位置。虽然最初提出问题时它可能不存在,但它现在位于 Object.entries() 的 MDN 页面上,标题为 Converting an Object to a Map,其中指出:
将对象转换为地图
new Map()
构造函数接受entries
的迭代。使用Object.entries
,您可以轻松地将Object
转换为Map
:const obj = foo: 'bar', baz: 42 ; const map = new Map(Object.entries(obj)); console.log(map); // Map foo: "bar", baz: 42
【讨论】:
【参考方案3】:是的,Map
构造函数采用键值对数组。
Object.entries
是 ES2017 (19.1.2.5) 中提供的新 Object 静态方法。
const map = new Map(Object.entries(foo: 'bar'));
map.get('foo'); // 'bar'
It's currently implemented in Firefox 46+ and Edge 14+ and newer versions of Chrome
如果您需要支持较旧的环境并且转译不是您的选择,请使用 polyfill,例如 georg 推荐的:
Object.entries = typeof Object.entries === 'function' ? Object.entries : obj => Object.keys(obj).map(k => [k, obj[k]]);
【讨论】:
一个“polyfill”会很简单:Object.entries = obj => Object.keys(obj).map(k => [k, obj[k]])
Object.entries
正确登陆 Node 7.x(没有标志)顺便说一句
不仅是 Node7 中的 Object.entries,它也是 ES2017 最终规范的一部分。因此,这应该是公认的答案,IMO
@AnilRedshift - 好吧,这个还是the generator function answer,因为 OP 要求提供一种避免中介的解决方案。
很遗憾,它不会。【参考方案4】:
const myMap = new Map(
Object
.keys(myObj)
.map(
key => [key, myObj[key]]
)
)
【讨论】:
融合@Ohar 和@TJCrowder 的解决方案:var buildMap2 = o => new Map(Object.keys(o).map(k => [k, o[k]]));
。
谢谢,因为我也需要对对象键进行排序!【参考方案5】:
您也可以使用lodash toPairs 方法:
const _ = require('lodash');
const map = new Map(_.toPairs(foo: 'bar'));
【讨论】:
【参考方案6】:我真的必须先将它转换成键值对数组的数组吗?
不,键值对数组的迭代器就足够了。您可以使用以下方法来避免创建中间数组:
function* entries(obj)
for (let key in obj)
yield [key, obj[key]];
const map = new Map(entries(foo: 'bar'));
map.get('foo'); // 'bar'
【讨论】:
很好的例子 - 只是给其他人的一个注释,你可能想在 for 循环条件之后做一个if(!obj.hasOwnProperties(key)) continue;
以确保你不会产生从对象原型继承的属性(除非你相信对象,但在使用 in
作为一个好习惯迭代对象时应该这样做)。
@Puiu 不,你不应该,这是一个坏习惯。如果你不信任这个对象,你也不能信任它的.hasOwnProperty
属性,你必须使用Object.prototype.hasOwnProperty.call(obj, key)
是的,我认为不打扰是最好的做法。您应该相信所有值得枚举的对象(即键值映射)没有任何可枚举的继承属性。 (当然是avoid enumerating arrays)。如果你有一个罕见的枚举其他东西的情况,并且你打扰了,你至少应该用call
正确地做到这一点。推荐obj.hasOwnProperties(key)
的所有约定似乎都不知道他们在做什么。
将 Object
转换为 Map
是一项昂贵的操作,并且 OP 特别要求没有中间体的解决方案。那么为什么这不是例外的答案呢?好吧,问这个可能是徒劳的,它只会让我烦恼。
@tmvnty 您可能需要拼出类型function* entries<T>(obj: T): Generator<readonly [keyof T, T[keyof T]]> …
。 yield [key, obj[key]] as const;
还可以帮助 TypeScript 意识到它产生的是元组,而不是数组。以上是关于如何将普通对象转换为 ES6 Map?的主要内容,如果未能解决你的问题,请参考以下文章