Метод JS Set.has () выполняет поверхностные проверки?

1

Если у меня есть набор объектов, например

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

и я сделаю

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

У меня будет положительный результат? Как Set обрабатывает ссылочные типы? Есть ли способ сказать, чтобы использовать пользовательскую проверку/предикат?

Показать ещё 1 комментарий
Теги:
ecmascript-6

4 ответа

1
Лучший ответ

Он ожидал, что любой родной JavaScript API сравнивает объекты по их ссылкам, а не их содержимому (включая мелкое сравнение):

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

Set не является исключением, он выполняет === сравнение для каждого значения, но NaN когда он просматривает значения, has или сохраняет уникальные значения.

Этого можно добиться, расширив Set и используя глубокое сравнение в методах has и т.д., Но это будет неэффективно.

Более эффективным способом является использование Map, потому что записи должны быть сохранены и извлечены нормализованными ключами, но предполагается, что фактические объекты будут сохранены. Это можно сделать с помощью JSON.stringify, но также желательно сортировать объектные ключи, поэтому может использоваться сторонняя реализация, такая как json-stable-stringify.

На данный момент, может быть, не так много преимуществ от расширения Set или Map поскольку большинство методов следует переопределить:

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

Согласно документам:

Объект Set позволяет хранить уникальные значения любого типа, будь то примитивные значения или ссылки на объекты.

Как вы добавляете объекты, их ссылки будут храниться внутри и проверка будет возвращать false, потому что ваши проезжает другой объект has метод.

На самом деле, ваш случай даже описан в разделе " Примеры" ссылки на метод has.

2

Что касается объектов, наборы обрабатывают уникальные ссылки.

new Set([ {a: 1}, {a: 1} ]) имеет два элемента.

var x = {a: 1}; new Set([ x, x ]); имеет один элемент.

Нет способа использовать функцию выборочного сравнения.

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

Выравнивание и идентичность равенства MDN

Ещё вопросы

Сообщество Overcoder
Наверх
Меню