ES6 中的地图与对象,何时使用?
Posted
技术标签:
【中文标题】ES6 中的地图与对象,何时使用?【英文标题】:Maps vs Objects in ES6, When to use? 【发布时间】:2015-12-12 13:00:09 【问题描述】:Ref: MDN Maps
当键在运行时之前是未知的,以及何时在对象上使用映射 所有的键都是相同的类型,所有的值都是相同的类型。
当存在对单个元素进行操作的逻辑时使用对象。
问题:
在对象上使用地图的适用示例是什么?特别是“什么时候密钥在运行时才未知?”
var myMap = new Map();
var keyObj = ,
keyFunc = function () return 'hey',
keyString = "a string";
// 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.get(keyFunc));
【问题讨论】:
是的,我注意到了。当我将函数设置为值时。 @JonathanLonowski 你能想到我什么时候应该这样做 :( 很难考虑用例。 您可以在您说要使用 Object 关联一些数据的 DOM 元素的地方使用它。除了使用元素的 ID 作为对象中的键之外,您还可以将元素本身用作 Map 中的键,这样您就不必关心元素是否具有 ID(或除对象引用之外的任何其他唯一标识符) 与否。 @RobG 只是一点点补充:在这种情况下,WeakMap
也可能会有所帮助。
我认为这建议将对象用作/用于记录,将地图用于所有其他类型的映射。对于记录,我指的是具有一组固定字段的数据结构,例如具有字段 name
和 id
的用户对象。
当我阅读 MDN 页面时,用例的要点列表比您引用的段落更有帮助。当然与您标题中提出的问题有关。
【参考方案1】:
在对象上使用地图的适用示例是什么?
我想你已经给出了一个很好的例子:当你使用对象(包括函数对象)作为键时,你至少需要使用Map
s。
尤其是“在运行时之前什么时候密钥是未知的?”
当它们在编译时未知时。简而言之,当您需要key-value collection 时,您应该始终使用Map
。需要集合的一个很好的指标是当您从集合中动态添加和删除值时,尤其是当您事先不知道这些值时(例如,它们是从数据库中读取的,由用户输入等)。
相反,当您在编写代码时知道对象具有哪些属性和多少属性时,您应该使用对象——当它们的形状是静态的时。正如@Felix 所说:当您需要record 时。需要的一个很好的指标是当字段具有不同的类型时,并且当您永远不需要使用括号表示法(或期望其中包含一组有限的属性名称)时。
【讨论】:
或者从另一个角度来看:每当您需要在数据级别(例如for..of
)而不是程序级别(例如for..in
)迭代对象的属性时,请使用Map
.有关此条款的更多信息in this response。
我还将添加一个注释,即无论何时您不知道您的密钥将是哪种类型并且您不希望字符串作为密钥数据类型,然后使用 map ***.com/questions/32600157/…
【参考方案2】:
当键在运行时之前未知,并且所有键的类型相同且所有值的类型相同时,对对象使用映射。
我不知道为什么有人会写出如此明显错误的东西。我不得不说,现在人们在 MDN 上发现越来越多的错误和/或有问题的内容。
那句话中的任何内容都不正确。使用映射的主要原因是当您需要对象值键时。值应该是相同类型的想法是荒谬的——尽管它们可能是,当然。在运行时之前不知道键的情况下不应该使用对象的想法同样荒谬。
【讨论】:
我不明白这个想法有什么荒谬之处?当您需要集合时,它们通常是严格类型的(当然也可能有例外)。另外,我认为不要再将对象用于集合(当Map
可用时)是个好建议。
集合通常是严格类型化的,这与说严格类型化的东西应该是一个集合在逻辑上是不同的。
是的,我认为这有点奇怪,但这个想法很好。我猜他们认为“在运行时密钥是未知的”已经收集了。有更好的措辞的想法吗?
同意。 MDN 有很好的文档,但他们应该坚持记录 API 文档,而不是试图提供编程建议。【参考方案3】:
我认为使用 ES2015 的 Map
只剩下两个理由来使用普通对象:
什么时候属性顺序不重要了?
如果您只有一个值和一些应该与其显式关联的函数(例如Promise
- 它是未来值的代理 - 和 then
/catch
)
如果您有一个类似结构/记录的数据结构,其中包含一组在“编译时”已知的静态属性(通常结构/记录不可迭代)
在所有其他情况下,您可能会考虑使用Map
,因为它保留了属性顺序并将程序(分配给Map
对象的所有属性)与数据级别(Map
本身中的所有条目)分开。
Map
的缺点是什么?
【讨论】:
这一行让我非常关心:“它可能比纯的、类似 hashmap 的对象要慢”,因为性能改进,我想用映射替换我的所有对象。但是你说它比较慢... 你是对的。Map
可能更快,因为它纯粹基于散列,而Object
稍微复杂一些。谢谢!【参考方案4】:
这个问题与 重复,但在它关闭之前,这里是my answer from over there:
除了其他答案之外,我发现地图比对象更笨拙和冗长。
obj[key] += x
// vs.
map.set(map.get(key) + x)
这很重要,因为更短的代码阅读速度更快,表达更直接,更好kept in the programmer's head。
另一方面:因为 set() 返回的是映射,而不是值,所以不可能链式赋值。
foo = obj[key] = x; // Does what you expect
foo = map.set(key, x) // foo !== x; foo === map
调试地图也更痛苦。在下面,您实际上看不到地图中的键。你必须编写代码才能做到这一点。
任何 IDE 都可以评估对象:
【讨论】:
这根本没有回答“在对象上使用地图的适用示例是什么?”这个问题 请不要交叉发布您的答案。不,这个问题不是重复的。【参考方案5】:Map
和 Object
之间的区别之一是:
Map
可以使用复杂数据类型作为其键。像这样:
const fn = function()
const m = new Map([[document.body, '***'], [fn, 'redis']]);
m.get(document.body) // '***'
m.get(fn) //'redis'
注意:对于复杂的数据类型,如果要获取值,必须传递与key相同的引用。
Object
,它只接受简单数据类型(number
,string
)作为它的key。
const a = ;
a[document.body] = '***';
console.log(a) //[object htmlBodyElement]: "***"
【讨论】:
【参考方案6】:Object
s 与Map
s 相似,两者都允许您将键设置为值、检索这些值、删除键以及检测键中是否存储了某些内容。正因为如此(并且因为没有内置的替代品),Object
s 在历史上一直被用作Map
s;但是,在某些情况下使用Map
更可取:
Object
的键是 String
s 和 Symbol
s,而它们可以是
Map
的任何值,包括函数、对象和任何原语。
Map
中的键是有序的,而添加到对象的键不是。因此,
迭代它时,Map
对象按顺序返回键
插入。
您可以使用size
属性轻松获取Map
的大小,同时
Object
中的属性数量必须手动确定。
Map
是可迭代的,因此可以直接迭代,而
遍历Object
需要以某种方式获取其密钥
并对其进行迭代。
Object
有一个原型,所以映射中有默认键
如果您不小心,可能会与您的钥匙发生碰撞。从 ES5 开始
可以使用map = Object.create(null)
绕过,但这是
很少做。
Map
在涉及频繁添加和
删除密钥对。
MDN
【讨论】:
以上是关于ES6 中的地图与对象,何时使用?的主要内容,如果未能解决你的问题,请参考以下文章