javascript的Set和普通的普通对象有什么区别?

问题描述 投票:2回答:3

在尝试解决这个question时,我了解了javascript的Set对象的存在。然后我检查了MDN's Set documentation,我在这里问的问题马上就出现了。

这场辩论始于前面提到的question's回答评论。我发现this线程也有助于辩论。

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

  • Set在其API中提供了“清晰”的方法,这是一个很好的功能
  • Set确保保持添加元素的顺序。普通对象不会。

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

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

javascript ecmascript-6 specifications
3个回答
1
投票

首先,here's a post的代码显示如何开始使用普通的Javascript对象进行类似集合的行为(有一些限制)。

并且,这是a set of objects(在ES5中工作)获得更多类似集合的行为。

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

如果您研究这些代码中的任何一个,您将看到一个普通的Javascript对象远远超过ES6集,在许多方面需要大量额外的编码才能解决。


以下是一些问题:

  1. 将对象指定为键将无法正常工作,因为所有对象都转换为"[object Object]"的字符串键,因此所有对象在类似集合的Javascript对象中具有相同的键。
  2. 将数字指定为键将转换为字符串表示形式,因此像4"4"这样的键会发生冲突。

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

如果查看this answer to a prior post and the code in that answer,您可以看到底层Javascript对象如何用作类似集合的行为的查找机制。虽然没有很多其他编码,但它有一些限制,因为Javascript对象需要一个字符串作为查找键。 ES6套装没有。因此,开箱即用的ES6 Set支持将对象作为元素。使用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]”,它根本不是你想要的。有关演示,请参阅here。它似乎适用于一个对象,但只要您在集合中有多个对象或为另一个对象设置该集合,它就根本不起作用,因为所有对象都将使用相同的键进行索引。

另一方面,使用实际的ES6设置,它可以原生地接受和使用对象 - 你不需要做任何特别的事情。

如果你想看看如何使用普通的Javascript对象作为查找机制尽可能地模仿ES6集,请阅读this answer。进一步的信息是located on github,你可以看到如何做一个常规的基于Javascript对象的集实现支持与this ObjectSet implementation Javascript对象。甚至还有一个ES6 Set polyfill here,它使用底层的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中,您可以看到生成here的唯一键。然后必须重新生成该唯一键并用于在集合中进行任何查找。


1
投票

集合不重复看到这个fiddle

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

1
投票

设置实例是对象。如果构造一个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添加或删除集合中的值不会影响set对象的普通属性。

如果有人希望仅使用ES5工具来实现像Set工具这样的工具,那么你可能需要做一些事情,比如维护一个值数组,或者按值类型执行一组数组。 .add().has()以及其他方法必须通过搜索将集合成员资格的规则强加于该值列表。可能需要进行一些优化以使搜索更有效,但ES6运行时具有优势,最值得注意的是运行时内部可以访问原始对象引用值和其他此类事物。

© www.soinside.com 2019 - 2024. All rights reserved.