如何将普通对象转换为 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.keysObject.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?的主要内容,如果未能解决你的问题,请参考以下文章

ES6 将可迭代转换为数组时间复杂度

ES6标准学习: 4数组的扩展

ES6 Set 和 Map

将数组转换为 ES6 可迭代

如何将 Mongoose 文档转换为普通对象?

如何将 Mongoose 文档转换为普通对象?