【问题标题】:ES6 Set allows duplicate array/objectES6 Set 允许重复的数组/对象
【发布时间】:2016-04-13 04:54:08
【问题描述】:

请看下面的脚本。我正在用 Chrome 测试它。

/*declare a new set*/
var items = new Set()

/*add an array by declaring as array type*/
var arr = [1,2,3,4];
items.add(arr);

/*print items*/
console.log(items); // Set {[1, 2, 3, 4]}

/*add an array directly as argument*/
items.add([5,6,7,8]);

/*print items*/
console.log(items); // Set {[1, 2, 3, 4], [5, 6, 7, 8]}

/*print type of items stored in Set*/
for (let item of items) console.log(typeof item); //object, object

/*check if item has array we declared as array type*/
console.log(items.has(arr)); // true

/*Now, check if item has array we added through arguments*/
console.log(items.has([5,6,7,8])); //false

/*Now, add same array again via argument*/
items.add([1,2,3,4]);

/*Set has duplicate items*/
console.log(items); // Set {[1, 2, 3, 4], [5, 6, 7, 8], [1, 2, 3, 4]}
  1. 为什么在 items.has([5,6,7,8]) 返回 false?
  2. 为什么允许重复值?我认为“一个集合位于不能包含重复值的有序值列表中”
  3. 如何访问items.add([5,6,7,8])添加的数组?

【问题讨论】:

  • [5, 6, 7, 8] !== [5, 6, 7, 8]这个代码也返回false,每个数组都是一个单独的对象。
  • “我认为一个集合在一个有序的值列表中” 列表是按定义排序的。集合通常不是。

标签: javascript ecmascript-6


【解决方案1】:
  1. 为什么它在 items.has([5,6,7,8]) 返回 false?

    来自MDN

    Set 对象允许您存储任何类型的唯一,无论是原始值还是对象引用

    使用引用而不是值来比较对象。 Sets 使用SameValueZero(x, y) 比较算法来比较值。如果 x 和 y 是 相同的对象值,它会说 返回 true。否则,返回false

  2. 为什么它允许重复值?我认为“一个集合在一个不能包含重复值的有序列表中”

    与#1 相同。如果集合中已经添加了相同的对象看起来不一样),则认为集合中已经存在非原始值。

  3. 如何访问items.add([5,6,7,8])添加的数组?

    您必须创建一个变量并将该变量添加到集合中。然后这个变量可以用来检查set是否有那个数组。

【讨论】:

  • 谢谢,我想传达的是,如果 Set 允许添加项目,即使它们没有参考集并且可能永远不会被访问。那么为什么要规定将此类项目添加到集合中,而这些项目可能永远无法在没有参考的情况下访问,而在这种情况下,我们没有参考。我并没有转移原始问题,只是想知道也许任何人都有理由证明 Set 中没有引用的项目。
  • @jeetaz 因为,您可以在集合中添加任何内容,然后使用for..of 访问。这是为了让添加元素的过程在您想要对其进行迭代时变得灵活。
  • 在这种情况下,无论如何它只是一个对象数组,可以像传统数组一样迭代。但足够公平!
【解决方案2】:

引用the specification:

Set 对象是 ECMAScript 语言值的集合。一个不同的值只能作为 Set 集合的一个元素出现一次。 使用 SameValueZero 比较算法区分不同的值。

(强调我的)

SameValueZero comparison algorithm 处理任何两个相同类型的参数(其中该类型不是nullundefined、字符串、数字、布尔值或符号),如下所示:

如果 x 和 y 是相同的 Object 值,则返回 true。否则,返回false

最终,这意味着对象是通过 reference 进行比较的(也就是说,实际上,“这两个对象是否指向内存中的相同位置?”)每次创建数组时使用方括号 ([]) 或构造函数调用 (new Array()) 在内存中创建 Arraynew 实例。当您保留对数组的引用时,它将匹配(例如arr === arr)。当您创建新实例并比较它们时,它们将匹配,即使它们的内容会比较相等(例如[1, 2, 3] !== [1, 2, 3])。

【讨论】:

  • 我明白你所说的通过引用比较的意思,但在这种情况下,添加到集合中的项目是无用的,因为我们没有参考。为什么它允许添加这样的项目而不是忽略它?我的意思是我不知道 Set 中有哪些项目存在但永远无法访问,因为我们没有可比较的参考。
  • 因为您可以稍后参考-e。 G。 `var nowIhaveReference = Array.from(items)[2]``
  • 但这不是我们可以用对象数组做的吗?
【解决方案3】:
  1. 数组比较不比较值,它比较引用,所以它返回 false。 [1] === [1] 将始终返回 false。
  2. 见参考MDN

Set 对象允许您存储任何类型的唯一值,无论是原始值还是对象引用。

您传递的是新对象而不是引用,因此它允许添加重复项。这实际上在视觉上相似但参考不同。

  1. 通过将引用分配给变量来访问添加的数组来传递引用。

【讨论】:

  • “你不能直接在 Javascript 中比较数组”——这是非常误导的。 [1] == [2] --- 这里我只是“直接”比较了 2 个数组
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-12-21
  • 2018-09-15
  • 2017-02-08
  • 2021-06-19
  • 2019-05-01
  • 2020-10-20
相关资源
最近更新 更多