当密钥都是字符串时,使用ES6 Map有什么意义?


35

普通对象键必须是字符串,而a Map可以具有任何类型的键。

但实际上我对此没有多大用处。几乎在所有情况下,我都发现自己还是使用字符串作为键。大概new Map()比慢{}。那么,还有其他原因为什么使用a Map而不是普通对象会更好?


3
像往常一样,MDN具有良好的比较。
克里斯·海斯

1
仅供参考,设置和获取地图似乎都更快
mpen

@mpen – jsperf现在关闭了。您确定map.set('foo', 123)执行速度比obj.foo = 123?如果是这样,那将非常令人惊讶
callum

@callum嗯..不,不是肯定的。您可能要编写一些新的性能测试。
mpen

Answers:


42

有一些原因使我Map比起普通对象({})更喜欢使用s 来存储运行时数据(缓存等):

  1. .size属性使我知道此Map中存在多少个条目;
  2. 各种实用方法- .clear().forEach()等;
  3. 他们默认提供了我的迭代器!

其他所有情况,例如传递函数参数,存储配置等,均使用普通对象编写。

另外,请记住:不要尝试过早优化代码。除非您的项目遇到性能问题,否则不要浪费时间进行普通对象与地图的基准测试。


1
Javascript使用的身份哈希码功能是什么?
Pacerier

1
@Pacerier ===:)
gustavohenke

如今,地图比普通对象要快得多。
jayarjo

@gustavohenke那不是真的。Map使用SameValueZero算法。developer.mozilla.org/en-US/docs/Web/JavaScript/...
lolmaus -安德烈·米哈伊洛夫

@ lolmaus-AndreyMikhaylov好的,但是我是否对Map使用s的东西说了些什么?
gustavohenke

4

我对此不确定,但我认为性能并不是使用Maps的原因。看看这个更新的jsperf页面:

http://jsperf.com/es6-map-vs-object-properties/73

看起来(至少在处理字符串时)对象比用于基本设置和获取的映射要快得多。


2
那不是您编写性能测试的方式。
Qix

6
那不是您编写有用评论的方式。如果您有其他建议的方法,请随时进行详细说明。具体来说,这些测试的编写方式有什么问题?它们以任何方式无效还是无益?
starlogodaniel

9
通过微基准测试的语言语义/构造只能相差一个变量。您的测试随迭代次数的不同而有所不同,其中一些将由于未使用结果而优化了其内部循环内容。一些测试会预先声明变量,而另一些测试会将变量声明与for循环内联-可能会导致不同的性能异常。
Qix

1
哎呀,你绝对正确。在我的辩护中,我的版本是对之前版本的改进,但是我错过了预声明和内部循环内容都已优化的内容。我正在与一位同事进行合作,该同事对我的草案进行了改进,并且认为可以解决这些问题:jsperf.com/es6-map-vs-object-properties/88。但是,我认为对不同的数据结构使用不同的循环样式是正确的。在实际使用中,人们会选择性能最好的循环结构,而Map和Object具有不同的“最佳”循环结构。无论如何,谢谢你的收获。
starlogodaniel

好吧,我现在知道了-它们过去比普通对象要慢,但是在最近的浏览器中已经进行了优化。
jayarjo

0

其他答案没有提及object和Maps 之间的最后一个区别:

Map对象保存键值对,并记住键的原始插入顺序

因此,在对其进行迭代时,Map对象将按插入顺序返回键。

来自MDN的引言,重点是我的


这是我决定Map在最近的项目中首次使用的主要原因。我有一个普通对象,需要在中显示<table>,每个属性都在特定行中显示。

let productPropertyOrder = [ "name", "weight", "price", "stocked" ];

let product =
{
    name: "Lasagne",
    weight: "1kg",
    price: 10,
    stocked: true
}

我编写了一个函数,Map根据所需的键顺序将对象转换为:

function objectToMap( obj, order )
{
    let map = new Map();

    for ( const key of order )
    {
        if ( obj.hasOwnProperty( key ) )
        {
            map.set( key, obj[ key ] );
        }
    }

    return map;
}

然后可以按照所需顺序迭代地图:

let productMap = objectToMap( product, productPropertyOrder );

for ( const value of productMap.values() )
{
    let cell = document.createElement( "td" );
    cell.innerText = value;
    row.appendChild( cell );
}

当然这有点人为的原因是,在遍历属性顺序时无需Map在过程中创建,就可以很好地显示它:

for ( const key of productPropertyOrder )
{
    if ( product.hasOwnProperty( key ) )
    {
        let value = product[ key ];
        // create cell
    }
}

但是,如果您有一个这样的对象数组并将要在许多地方显示它们,则首先将它们全部转换为地图是有意义的。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.