如何将普通对象转换为ES6映射?

cal*_*lum 100 javascript ecmascript-6

出于某种原因,我无法在MDN文档中找到这个简单的东西(也许我只是错过了它).

我希望这可行:

const map = new Map({foo: 'bar'});

map.get('foo'); // 'bar'
Run Code Online (Sandbox Code Playgroud)

......但是第一行抛出 TypeError: (var)[Symbol.iterator] is not a function

如何从普通对象制作地图?我是否真的必须先将其转换为键值对数组?

nil*_*ils 150

是的,Map构造函数采用一组键值对.

Object.entriesES2017(19.1.2.5)中提供的一种新的Object静态方法.

const map = new Map(Object.entries({foo: 'bar'}));

map.get('foo'); // 'bar'
Run Code Online (Sandbox Code Playgroud)

它目前已在Firefox 46+和Edge 14+以及更新版本的Chrome中实施

如果您需要支持较旧的环境并且不能选择转换,请使用polyfill,例如georg推荐的polyfill:

Object.entries = typeof Object.entries === 'function' ? Object.entries : obj => Object.keys(obj).map(k => [k, obj[k]]);
Run Code Online (Sandbox Code Playgroud)

  • `Object.entries`在Node 7.x中正确登陆(没有标志)btw (4认同)
  • "polyfill"将相当简单:`Object.entries = obj => Object.keys(obj).map(k => [k,obj [k]])` (3认同)
  • 不仅是Node7中的Object.entries,它也是ES2017最终规范的一部分.因此,这应该是公认的答案,IMO (2认同)
  • 不幸的是,它不会。 (2认同)

T.J*_*der 73

使用生成器函数查看nils的答案Object.entries和/或bergi的答案.虽然Object.entries在问题被问到时尚未出现在规范中,但它是在第4阶段,因此在2016年4月(仅仅)回到polyfill并使用是安全的.(更多关于这里的阶段.)和发电机功能在ES2015.OP特别要求避免中间人,虽然发电机并没有完全避免这种情况,但它比下面或(稍微)做得更好Object.enties.

FWIW,使用Object.entries:

  • 创建[name, value]要传递给的数组数组new Map
  • Map构造函数调用阵列上的函数来获得一个迭代器; 数组创建并返回数组处理器对象.
  • Map构造函数使用了迭代器对象获取的条目(该[name, value]阵列),并建立映射

使用发电机:

  • 作为调用生成器函数的结果,创建生成器对象
  • Map构造函数调用生成器对象的函数从它那里得到一个迭代器; 生成器对象返回自身
  • Map构造函数使用生成器对象(作为一个迭代)来获得条目(在[name, value]阵列)和构建地图

所以:少一个中介(数组来自Object.entries).

但是,使用Object.entries更简单,并且99.999%的时间创建该数组不是问题.真的,任何一个.但他们都比下面更好.:-)


原始答案:

要初始化a Map,可以使用任何将键/值对作为数组返回的迭代器,例如数组数组:

const map = new Map([
    ['foo', 'bar']
]);
Run Code Online (Sandbox Code Playgroud)

没有从对象到地图的内置转换,但它很容易完成Object.keys:

const map = new Map();
let obj = {foo: 'bar'};
Object.keys(obj).forEach(key => {
    map.set(key, obj[key]);
});
Run Code Online (Sandbox Code Playgroud)

当然,您可以给自己一个工作函数来处理:

function buildMap(obj) {
    let map = new Map();
    Object.keys(obj).forEach(key => {
        map.set(key, obj[key]);
    });
    return map;
}
Run Code Online (Sandbox Code Playgroud)

然后

const map = buildMap({foo: 'bar'});
Run Code Online (Sandbox Code Playgroud)

或者这里看起来更像l33t(还是那件事?)版本:

function buildMap(obj) {
    return Object.keys(obj).reduce((map, key) => map.set(key, obj[key]), new Map());
}
Run Code Online (Sandbox Code Playgroud)

(是的,Map#set返回地图参考.有些人认为,这是一abusagereduce.)

或者我们真的可以在默默无闻中超越:

const buildMap = o => Object.keys(o).reduce((m, k) => m.set(k, o[k]), new Map());
Run Code Online (Sandbox Code Playgroud)

不,我永远不会那样做真的.:-)

  • 参见`new Map(Object.entries(object))`/sf/answers/2565119091/ (16认同)

Ber*_*rgi 30

我是否真的必须先将其转换为键值对数组?

不,键值对数组的迭代器就足够了.您可以使用以下内容来避免创建中间数组:

function* entries(obj) {
    for (let key in obj)
        yield [key, obj[key]];
}

const map = new Map(entries({foo: 'bar'}));
map.get('foo'); // 'bar'
Run Code Online (Sandbox Code Playgroud)

  • 完美使用发电机,谢谢! (3认同)
  • @Puiu不,你不应该,这是一个坏习惯。如果您不信任该对象,则也不能信任它的.hasOwnProperty属性,并且必须使用Object.prototype.hasOwnProperty.call(obj,key) (2认同)
  • 是的,我认为最好不要这样做。您应该信任所有值得枚举的对象(即键值映射)不具有任何可枚举的继承属性。(当然可以[避免枚举数组](/sf/ask/35035311/))。如果您很少有列举其他事情的麻烦,那么您至少应该使用`call`正确地做到这一点。推荐obj.hasOwnProperties(key)的所有约定似乎都不知道它们在做什么。 (2认同)
  • 将“对象”转换为“地图”是一项昂贵的操作,OP专门要求提供无中间件的解决方案。那么,为什么这不是例外的答案呢?好吧,问这可能是徒劳的,这让我很烦。 (2认同)

And*_*ems 9

Nils的答案描述了如何将对象转换为地图,我发现这非常有用.但是,OP也想知道这些信息在MDN文档中的位置.虽然在最初询问问题时它可能不存在,但它现在位于将对象转换为地图标题下的Object.entries()的MDN页面上,其中指出:

将对象转换为地图

new Map()构造函数接受的迭代entries.有了Object.entries,您可以轻松转换ObjectMap:

const obj = { foo: 'bar', baz: 42 }; 
const map = new Map(Object.entries(obj));
console.log(map); // Map { foo: "bar", baz: 42 }
Run Code Online (Sandbox Code Playgroud)


Yai*_*evy 7

ES6

将对象转换为地图:

const objToMap = (o) => new Map(Object.entries(o));
Run Code Online (Sandbox Code Playgroud)

将地图转换为对象:

const mapToObj = (m) => [...m].reduce( (o,v)=>{ o[v[0]] = v[1]; return o; },{} )
Run Code Online (Sandbox Code Playgroud)

注意:mapToObj 函数假定映射键是字符串(否则会失败)

  • 您可以执行以下操作将地图转换回对象:`Object.fromEntries(map.entries())` (4认同)

Oha*_*har 6

const myMap = new Map(
    Object
        .keys(myObj)
        .map(
            key => [key, myObj[key]]
        )
)
Run Code Online (Sandbox Code Playgroud)

  • @Ohar 和 @TJCrowder 解决方案的融合:`var buildMap2 = o => new Map(Object.keys(o).map(k => [k, o[k]]));`。 (3认同)