JS Set.has()方法会进行浅层检查吗?

时间:2018-07-11 20:03:19

标签: javascript ecmascript-6

如果我有一组对象,例如

const s = new Set();
s.add({a: 1, b: 2});
s.add({a: 2, b: 2});

我会做

s.has({a: 1, b: 2});

我会得到正面的结果吗? Set如何处理引用类型?有没有办法告诉它使用自定义检查器/谓词?

4 个答案:

答案 0 :(得分:3)

根据docs

  

Set对象使您可以存储任何类型的唯一值,无论是否   基本值或对象引用。

在添加对象时,它们的引用将存储在内部,并且由于将不同的对象传递给false方法,因此检查将返回has

实际上,您的案件甚至涵盖在Examples section of the has method reference中。

答案 1 :(得分:2)

关于对象,Set处理唯一的引用

new Set([ {a: 1}, {a: 1} ])有两项。

var x = {a: 1}; new Set([ x, x ]);有一项。

没有办法让Set使用自定义比较功能。

答案 2 :(得分:1)

期望任何本机JavaScript API均通过引用而不是内容(包括浅表比较)来比较对象:

({a: 1, b: 2}) !== ({a: 1, b: 2})

Set不是排除项,它是does === comparison for every value but NaN,当它使用has查找值或存储唯一值时。

这可以通过扩展Set并在has等方法中使用深度比较来实现,但效率不高。

一种更有效的方法是使用Map,因为应该使用规范化的键来存储和检索条目,但是应该存储实际的对象。可以使用JSON.stringify来完成,但是对象键也应该优先排序,因此可以使用第三方实现,例如json-stable-stringify

在这一点上,扩展SetMap可能不会带来太多好处,因为应该重写大多数方法:

class DeepSet {
  constructor (iterable = []) {
    this._map = new Map();
    for (const v of iterable) {
      this.add(v);
    }
  }

  _getNormalizedKey(v) {
    // TODO: sort keys
    return (v && typeof v === 'object') ? JSON.stringify(v) : v;
  }

  add(v) {
    this._map.set(this._getNormalizedKey(v), v);
    return this;
  }

  has(v) {
    return this._map.has(this._getNormalizedKey(v));
  }

  // etc
}

请注意,此集合仅适用于可以正确序列化为JSON的普通对象。可能还有其他方法可以序列化对象内容,但是没有一种方法可以正确处理所有可能的值,例如符号和类实例。

答案 3 :(得分:1)

您无法比较引用(例如数组和对象)是否相等。您可以比较值!!!

const s = new Set();
let a = {a: 1, b:2};
let b = {a: 2, b: 3};
s.add(a);
s.add(b);

s.has(a); //true

check the answer I just wrote on the linked page