我刚刚发现了这个特点:
Map: Map对象是简单的键/值映射。
这让我很困惑。常规JavaScript对象是字典,那么Map与字典有什么不同呢?从概念上讲,它们是相同的(根据Stack Overflow的另一个问题)
文档也没有帮助:
Map对象是键/值对的集合,其中键和值都可以是任意的ECMAScript语言值。不同的键值只能出现在Map集合中的一个键/值对中。使用创建Map时选择的比较算法进行区分的不同键值。
Map对象可以按插入顺序迭代其元素。Map对象必须使用哈希表或其他机制来实现,这些机制提供的访问时间平均与集合中元素的数量呈次线性关系。本Map对象规范中使用的数据结构仅用于描述Map对象所需的可观察语义。它并不是一个可行的实现模型。
听起来还是像个物件,显然我错过了什么。
为什么JavaScript获得一个(受良好支持的)Map对象?它能做什么?
除了按定义良好的顺序可迭代,以及能够使用任意值作为键(除了-0)之外,map还很有用,原因如下:
The spec enforces map operations to be sublinear on average.
Any non-stupid implementation of object will use a hash table or similar, so property lookups will probably be constant on average. Then objects could be even faster than maps. But that is not required by the spec.
Objects can have nasty unexpected behaviors.
For example, let's say you didn't set any foo property to a newly created object obj, so you expect obj.foo to return undefined. But foo could be built-in property inherited from Object.prototype. Or you attempt to create obj.foo by using an assignment, but some setter in Object.prototype runs instead of storing your value.
Maps prevent these kind of things. Well, unless some script messes up with Map.prototype. And Object.create(null) would work too, but then you lose the simple object initializer syntax.
除了按定义良好的顺序可迭代,以及能够使用任意值作为键(除了-0)之外,map还很有用,原因如下:
The spec enforces map operations to be sublinear on average.
Any non-stupid implementation of object will use a hash table or similar, so property lookups will probably be constant on average. Then objects could be even faster than maps. But that is not required by the spec.
Objects can have nasty unexpected behaviors.
For example, let's say you didn't set any foo property to a newly created object obj, so you expect obj.foo to return undefined. But foo could be built-in property inherited from Object.prototype. Or you attempt to create obj.foo by using an assignment, but some setter in Object.prototype runs instead of storing your value.
Maps prevent these kind of things. Well, unless some script messes up with Map.prototype. And Object.create(null) would work too, but then you lose the simple object initializer syntax.
除了其他答案之外,我还发现map比对象操作起来更笨拙和冗长。
obj[key] += x
// vs.
map.set(map.get(key) + x)
这一点很重要,因为较短的代码读起来更快,表达更直接,并且更好地记在程序员的脑海里。
另一方面:因为set()返回的是映射,而不是值,所以不可能链式赋值。
foo = obj[key] = x; // Does what you expect
foo = map.set(key, x) // foo !== x; foo === map
调试地图也更加痛苦。下图中,你实际上看不到地图中的键是什么。你必须编写代码才能做到这一点。
对象可以被任何IDE计算:
这是我记住它的一个简单方法:KOI
Keys. Object key is strings or symbols. Map keys can also be numbers (1 and "1" are different), objects, NaN, etc. It uses === to distinguish between keys, with one exception NaN !== NaN but you can use NaN as a key.
Order. The insertion order is remembered. So [...map] or [...map.keys()] has a particular order.
Interface. Object: obj[key] or obj.a (in some language, [] and []= are really part of the interface). Map has get(), set(), has(), delete() etc. Note that you can use map[123], but that is using it as a plain JavaScript object.