繁体   English   中英

javascript的Set和常规普通对象之间有什么区别?

[英]What are the differences between javascript's Set and a regular plain object?

在尝试解决此问题时 ,我了解了javascript的Set对象的存在。 然后,我检查了MDN的Set文档 ,然后立即弹出我在这里提出的问题。

这场辩论始于上述问题的答案评论。 我发现线索也有助于辩论。

到目前为止,我本人可以从辩论中得出的结论是:

  • Set在其API中提供了“清除”方法,这是一项很好的功能

  • Set确保添加的元素的顺序得以保留。 普通对象没有。

任何人都可以提供明确的结论吗? 也许我不应该将两者进行比较...但是我仍然认为这是一个合理的问题,其他人很可能在了解Set后会问同样的问题。

无论如何,最初促使我问这个问题的是编辑 MDN的Set规范,并添加从此处获得的结论。 但是在这里开发完线程之后,我认为我不应该这样做,也许Set的规范实际上不应提及“最终提供相似功能的普通对象该如何处理”。 至少有人问自己这个问题,仍然可以在SO中找到它,并享受这里添加的见解/贡献。

首先, 这是一篇包含代码的文章 ,该文章显示了如何开始将纯Javascript对象用于类似集合的行为(有一些限制)。

并且,这是一组对象 (在ES5中可用),用于获得更多类似集合的行为。

并且,这里是ES5中实现的Set对象的部分ES6 polyfill

如果学习这些代码,您会发现普通的Javascript对象在很多方面都远不及ES6集,而这需要大量额外的代码来解决。


这里有几个问题:

  1. 将对象分配为键将无法正常工作,因为所有对象都将转换为字符串"[object Object]"因此所有对象在类似集合的Javascript对象中都具有相同的键。

  2. 将数字分配为键将转换为字符串表示形式,因此键4"4"将发生冲突。

ES6 Set对象没有这些限制。 这是关于这两个问题的更多讨论:

如果您看一下先前文章的答案以及该答案中的代码 ,则可以看到如何将底层Javascript对象用作类似集合的行为的查找机制。 尽管没有很多其他编码,但是它有一些局限性,因为Javascript对象需要使用字符串作为查找键。 ES6集没有 因此,开箱即用的ES6集支持将对象作为元素。 将Javascript对象用作穷人的集合不支持将对象作为集合中的元素。

当您要将对象添加到基于Javascript的普通对象集中时,这变得最重要。

// create a set-like object
var mySet = {};

// create an object and put it in the set
var myObj = {greeting: "hello"};
mySet[myObj] = true;

因为Javascript对象需要一个字符串键,所以它将调用myObj.toString()来获得这样的键。 如果没有toString()方法的自定义覆盖,它将以“ [object Object]”的形式出现,这根本不是您想要的。 请参阅此处的演示。 它似乎适用于一个对象,但是一旦集合中有多个对象或为另一个对象设置了集合,则它将根本不起作用,因为所有对象都将使用相同的键进行索引。

另一方面,有了一个实际的ES6集,它就可以自然地接受并与对象一起工作-您不必做任何特殊的事情。

如果您想了解如何使用普通Javascript对象作为查找机制来尽可能接近地模拟ES6集,请阅读此答案 更多信息位于github上 ,您可以其中看到要使常规的基于Javascript对象的集实现支持此ObjectSet实现的 Java对象的操作。 这里甚至还有一个ES6 Set polyfill 它使用底层Javacript对象作为其存储机制。


第二个问题是基于Javascript对象的集合实现,这也是由于字符串键的要求。 如果您这样做:

var mySet = {};
mySet[4] = true;
mySet["4"] = true;

您将最终只得到其中一个项目。 这是因为mySet[4] = true; 4转换为字符串"4"以用作键。 如果您仅在集合中使用字符串或仅在集合中使用数字,则可以轻松解决此问题,但是如果集合中同时包含字符串和数字,则javascript对象库集合实现无法区分4"4"因此不会将它们视为集合中的单独项目。 ES6确实做到了这一点。

同样,有可能使用更多代码来解决此问题。 如果您手动进行toString()转换以创建密钥,则可以在密钥值前添加一些类型信息,以便在上面的示例中,数字4的密钥变为"num_4"而不仅仅是“ 4”。 为了防止与字符串““ num_4”`发生冲突,您还必须对字符串类型执行相同的操作。 而数字并不是这个问题的唯一类型。 实际上,在此ES6 Set polyfill中,您可以在此处看到正在生成的唯一密钥。 然后,必须重新生成该唯一密钥,并将其用于集合中的任何查找。

集不重复,看到这个小提琴

var mySet = new Set();

mySet.add(1);
mySet.add(5);
mySet.add("some text");


console.log('after adding duplicate  values ')
console.log('size='+mySet.size ) // size is 3


mySet.add("some text"); // adding duplicate value
console.log('after adding duplucate  value ')
console.log('size='+mySet.size ) // size is still 3

集合实例是对象。 如果构造一个Set,则可以自由地向其添加属性,就像Date或Array的实例一样:

var s = new Set();
s.name = "Herman";
s.shoeSize = 12;
console.dir(s); // just like an Object!
s.add(17);
if (s.has(17)) alert("yup!"); // yup!
if (17 in s) alert("yup!"); // no alert here!

Set原型公开的行为提供的功能实际上与对象的性质无关,除了对对象的引用属于可以与该API一起使用的各种值。 通过该API在集合中添加或删除值对集合对象的普通属性没有影响。

如果希望只使用ES5工具来实现Set工具之类的工具,则您必须执行一些操作,例如维护值数组或按值类型排列一组数组。 .add().has()等方法可能必须通过搜索在该值列表上强加集合成员资格的规则。 可能可以进行一些优化以提高搜索效率,但是ES6运行时具有优势,最显着的是运行时内部可以访问原始对象引用值和其他类似内容。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM