我刚刚发现了这个特点:

Map: Map对象是简单的键/值映射。

这让我很困惑。常规JavaScript对象是字典,那么Map与字典有什么不同呢?从概念上讲,它们是相同的(根据Stack Overflow的另一个问题)

文档也没有帮助:

Map对象是键/值对的集合,其中键和值都可以是任意的ECMAScript语言值。不同的键值只能出现在Map集合中的一个键/值对中。使用创建Map时选择的比较算法进行区分的不同键值。

Map对象可以按插入顺序迭代其元素。Map对象必须使用哈希表或其他机制来实现,这些机制提供的访问时间平均与集合中元素的数量呈次线性关系。本Map对象规范中使用的数据结构仅用于描述Map对象所需的可观察语义。它并不是一个可行的实现模型。

听起来还是像个物件,显然我错过了什么。

为什么JavaScript获得一个(受良好支持的)Map对象?它能做什么?


当前回答

我看到Minko Gechev的这篇文章,清楚地解释了主要的区别。

其他回答

除了上面提到的可用性差异,如果你对大型对象的性能差异更感兴趣,普通对象在chrome上设置、更新和删除大量数据时似乎要快2倍。

Experiment here: https://perf.link/#eyJpZCI6ImNncmtpcGdlMzhsIiwidGl0bGUiOiJGaW5kaW5nIG51bWJlcnMgaW4gYW4gYXJyYXkgb2YgMTAwMCIsImJlZm9yZSI6ImNvbnN0IGRhdGEgPSBbLi4uQXJyYXkoMTAwMDAwKS5rZXlzKCldXG4iLCJ0ZXN0cyI6W3sibmFtZSI6IkZpbmQgaXRlbSAxMDAiLCJjb2RlIjoiY29uc3Qgb2JqID0ge31cbmZvciAoY29uc3QgdiBvZiBkYXRhKSB7XG4gICBvYmpbdl0gPSB2XG59XG5cbmZvciAoY29uc3QgdiBvZiBkYXRhKSB7XG4gICBvYmpbdl0gPSB2ICsgMVxufVxuXG5mb3IgKGNvbnN0IHYgb2YgZGF0YSkge1xuICAgZGVsZXRlIG9ialt2XVxufSIsInJ1bnMiOlsxMTUsMTE1LDExNSwxMTUsMTE1LDExNSwxMDksMTE1LDEwOSwxMTUsMTE1LDExNSwxMDksMTE1LDExNSwxMTUsMTA5LDEwOSwxMDksMTE1LDEwOSwxMDksMTE1LDEwOSwxMTUsMTA5LDEwOSwxMTUsMTA5LDExNSwxMDksMTE1LDEwOSwxMDksMTA5LDEwOSwxMDksMTA5LDExNSwxMDksMTA5LDEwOSwxMDksMTE1LDEwOSwxMDksMTA5LDEwOSwxMDksMTE1LDEwOSwxMDksMTA5LDEwOSwxMDksMTA5LDEwOSwxMDksMTA5LDEwOSwxMDksMTA5LDEwOSwxMTUsMTA5LDEwOSwxMDksMTA5LDEwOSwxMDksMTA5LDEwOSwxMTUsMTE1LDEwOSwxMDksMTA5LDEwOSwxMDksMTA5LDEwOSwxMDksMTA5LDEwOSwxMDksMTA5LDEwOSwxMDksMTA5LDEwOSwxMDksMTA5LDEwOSwxMDksMTA5LDEwOSwxMDksMTA5LDEwOSwxMDldLCJvcHMiOjExMH0seyJuYW1lIjoiRmluZCBpdGVtIDIwMCIsImNvZGUiOiJjb25zdCBvYmogPSBuZXcgTWFwKClcbmZvciAoY29uc3QgdiBvZiBkYXRhKSB7XG4gICBvYmouc2V0KHYsIHYpXG59XG5cbmZvciAoY29uc3QgdiBvZiBkYXRhKSB7XG4gICBvYmouc2V0KHYsIHYgKyAxKVxufVxuXG5mb3IgKGNvbnN0IHYgb2YgZGF0YSkge1xuICAgb2JqLmRlbGV0ZSh2KVxufSIsInJ1bnMiOls2Myw1Nyw1Nyw2Myw1Nyw2Myw1Nyw1Nyw1Nyw2Myw1Nyw1Nyw1Nyw1Nyw1Nyw1Nyw1Nyw1Nyw1Nyw1Nyw1Nyw1Nyw1Nyw1Nyw1Nyw1Nyw1Nyw1Nyw1Nyw1Nyw1Nyw2Myw1Nyw1Nyw1Nyw1Nyw1Nyw1Nyw1Nyw1Nyw1Nyw1Nyw1Nyw1Nyw1Nyw1Nyw1Nyw1Nyw1Nyw1Nyw1Nyw1Nyw1Nyw1Nyw1Nyw1Nyw1Nyw1Nyw1Nyw1Nyw1Nyw1Nyw1Nyw1Nyw1Nyw1Nyw1Nyw1Nyw1Nyw1Nyw1Nyw1Nyw1Nyw1Nyw1Nyw1Nyw1Nyw1Nyw1Nyw1Nyw1Nyw1Nyw1Nyw1Nyw1Nyw1Nyw1Nyw1Nyw1Nyw1Nyw1Nyw1Nyw1Nyw1Nyw1Nyw1Nyw1Nyw1Nyw1Nyw1N10sIm9wcyI6NTd9XSwidXBkYXRlZCI6IjIwMjItMDYtMTVUMTg6MTQ6MjYuNjA2WiJ9

TL;DR:你不能在对象中使用键' length'来存储值,但在Map中可以。

对于我来说,不使用object而使用Map的实际考虑是,从实际的角度来看,object的键不是字符串或数字,而是字符串或数字的子集。具体来说,使用与原型的属性名或众所周知的属性冲突的键可能会导致问题。例如,存储具有键长度的值可能会使使用length键来确定给定对象是否为数组的代码混淆。

简介:

Object: A data structure in which data is stored as key value pairs. In an object the key has to be a number, string, or symbol. The value can be anything so also other objects, functions, etc. An object is a nonordered data structure, i.e. the sequence of insertion of key value pairs is not remembered ES6 Map: A data structure in which data is stored as key value pairs. In which a unique key maps to a value. Both the key and the value can be in any data type. A map is an iterable data structure. This means that the sequence of insertion is remembered and that we can access the elements in e.g. a for..of loop.

关键的不同点:

Map是有序的且可迭代的,而object不是有序的且不可迭代的(也就是说它们没有[符号]。迭代器]属性。但是,你可以在语法中使用for..遍历键。) 我们可以将任何类型的数据作为Map键,而对象只能将数字、字符串或符号作为键。 Map继承自Map.prototype。这提供了各种实用函数和属性,使Map对象的工作更加容易。

例子:

对象:

让obj = {}; //添加属性到对象 obj。Prop1 = 1; Obj [2] = 2; //获取对象属性的nr console.log(种(obj) . length) //删除属性 删除obj [2] console.log (obj)

Map:

const myMap = new Map(); const keyString = 'a string', keyObj = {}, keyFunc = function() {}; // setting the values myMap.set(keyString, "value associated with 'a string'"); myMap.set(keyObj, 'value associated with keyObj'); myMap.set(keyFunc, 'value associated with keyFunc'); console.log(myMap.size); // 3 // getting the values console.log(myMap.get(keyString)); // "value associated with 'a string'" console.log(myMap.get(keyObj)); // "value associated with keyObj" console.log(myMap.get(keyFunc)); // "value associated with keyFunc" console.log(myMap.get('a string')); // "value associated with 'a string'" // because keyString === 'a string' console.log(myMap.get({})); // undefined, because keyObj !== {} console.log(myMap.get(function() {})) // undefined, because keyFunc !== function () {}

来源:中数

对象的行为类似于字典,因为JavaScript是动态类型的,允许您随时添加或删除属性。

但是Map()更好,因为它:

提供get、set、has和delete方法。 接受任何类型的键,而不仅仅是字符串。 提供一个易于for-of使用的迭代器,并维护结果的顺序。 在迭代或复制过程中不会出现原型和其他属性的边缘情况。 支持数百万项。 非常快。

如果需要字典,则使用Map()。

但是,如果您只使用基于字符串的键,并且需要最大的读取性能,那么对象可能是更好的选择。这是因为JavaScript引擎在后台将对象编译为c++类,并且属性的访问路径比Map().get()的函数调用要快得多。

这些类也被缓存,所以创建一个具有完全相同属性的新对象意味着引擎将重用一个现有的后台类。添加或删除属性会导致类的形状改变,并重新编译支持类,这就是为什么将一个对象用作添加和删除大量内容的字典会非常慢,但是在不更改对象的情况下读取现有键会非常快。

因此,如果您有一个写一次读的繁重的工作负载和字符串键,那么您可以使用对象作为高性能的字典,但对于其他所有事情使用Map()。

我认为到目前为止答案中还没有提到以下几点,我认为它们值得一提。


地图可以更大

在Chrome中,我可以使用Map获得1670万个键/值对,而使用常规对象可以获得1110万个键/值对。带地图的情侣数量几乎增加了50%。它们在崩溃前都占用了大约2gb的内存,所以我认为可能与chrome的内存限制有关(是的,尝试填充2个地图,在崩溃前你只能得到830万对)。你可以用下面的代码自己测试它(显然,分开运行它们,而不是同时运行):

var m = new Map();
var i = 0;
while(1) {
    m.set(((10**30)*Math.random()).toString(36), ((10**30)*Math.random()).toString(36));
    i++;
    if(i%1000 === 0) { console.log(i/1000,"thousand") }
}
// versus:
var m = {};
var i = 0;
while(1) {
    m[((10**30)*Math.random()).toString(36)] = ((10**30)*Math.random()).toString(36);
    i++;
    if(i%1000 === 0) { console.log(i/1000,"thousand") }
}

对象已经有了一些属性/键

这个问题以前让我犯过错误。常规对象有toString, constructor, valueOf, hasOwnProperty, isPrototypeOf和其他一堆预先存在的属性。对于大多数用例来说,这可能不是一个大问题,但它曾经给我带来过问题。

地图会变慢:

由于.get函数调用开销和缺乏内部优化,Map在某些任务中可能比普通的旧JavaScript对象慢得多。