【问题标题】:How to convert a plain object into an ES6 Map?如何将普通对象转换为 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'sObject.entries 确实是比Object.keys 更好的方法,而bergi 的生成器函数方法比Object.keysObject.entries 更直接。

标签: javascript ecmascript-6


【解决方案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.entriesES2017 (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 意识到它产生的是元组,而不是数组。
        猜你喜欢
        • 2016-09-14
        • 1970-01-01
        • 2019-04-05
        • 2016-07-13
        • 2020-01-25
        相关资源
        最近更新 更多