Does JS Set.has() method do shallow checks?

与世无争的帅哥 提交于 2021-02-11 06:36:30

问题


If I have a set of objects, like

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

and I will do

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

Will I have a positive result? How does Set handle reference types? Is there a way to tell it to use custom checker/predicate?


回答1:


It's expected that any native JavaScript API compare objects by their references and not their contents (including shallow comparison):

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

Set isn't an exclusion, it does === comparison for every value but NaN when it looks up values with has or stores unique values.

This could be achieved by extending Set and using deep comparison in has, etc. methods but it would be inefficient.

A more efficient way is to use Map instead, because entries should be stored and retrieved by normalized keys, but actual objects are supposed to be stored. This can be done by using JSON.stringify, but object keys should be preferable sorted as well, so third-party implementation like json-stable-stringify may be used.

At this point there are may be not much benefits from extending either Set or Map because most methods should be overridden:

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
}

Notice that this set is intended only for plain objects that can be correctly serialized to JSON. There may be other ways to serialize object contents but none of them will handle all possible values correctly, e.g. symbols and class instances.




回答2:


According to docs:

The Set object lets you store unique values of any type, whether primitive values or object references.

As you are adding objects, their references will be stored internally and your check will return false because your are passing different object to has method.

Actually, your case is even covered in the Examples section of the has method reference.




回答3:


In regards to objects, Sets handle unique references.

new Set([ {a: 1}, {a: 1} ]) has two items.

var x = {a: 1}; new Set([ x, x ]); has one item.

There is no way to have Set use a custom comparison function.




回答4:


You can't compare references like arrays and objects for equality. You can compare values though!!!

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

MDN equality comparisons and sameness



来源:https://stackoverflow.com/questions/51293422/does-js-set-has-method-do-shallow-checks

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!