Строка JSON для набора

110

Как бы один JSON.stringify () в комплект ?

Что не работало в Chromium 43:

var s = new Set(['foo', 'bar']);

JSON.stringify(s); // -> "{}"
JSON.stringify(s.values()); // -> "{}"
JSON.stringify(s.keys()); // -> "{}"

Я ожидал получить что-то похожее на сериализованный массив.

JSON.stringify(["foo", "bar"]); // -> "["foo","bar"]"
МитМаро
источник

Ответы:

117

JSON.stringify не работает напрямую с наборами, потому что данные, хранящиеся в наборе, не сохраняются как свойства.

Но вы можете преобразовать набор в массив. Тогда вы сможете правильно натянуть его.

Любой из следующих вариантов поможет:

JSON.stringify([...s]);
JSON.stringify([...s.keys()]);
JSON.stringify([...s.values()]);
JSON.stringify(Array.from(s));
JSON.stringify(Array.from(s.keys()));
JSON.stringify(Array.from(s.values()));
Ориол
источник
2
Я собирался сделать предложение Array.from(). Но это выглядит идиомически лучше.
TaoPR 02
4
Просто чтобы добавить ссылку, у MDN есть несколько примеров этой и других связанных с ней техник
Амит
5
JSON.stringify([_ for (_ of s)])
Понимание
1
Все отличные способы сделать это, к сожалению, они не работают в Chromium 43 из коробки, так как spread и Array.from еще не реализованы. Похоже, что Бабель спешит на помощь.
MitMaro 02
2
Текущее предложение по улучшению значения по умолчанию Set.prototype.toJSON: github.com/DavidBruant/Map-Set.prototype.toJSON
Oncle Tom
35

Используйте этот JSON.stringifyзаменитель:

(поскольку toJSONэто устаревший артефакт, и лучший подход - использовать пользовательскийreplacer , см. https://github.com/DavidBruant/Map-Set.prototype.toJSON/issues/16 )

function Set_toJSON(key, value) {
  if (typeof value === 'object' && value instanceof Set) {
    return [...value];
  }
  return value;
}

Затем:

const fooBar = { foo: new Set([1, 2, 3]), bar: new Set([4, 5, 6]) };
JSON.stringify(fooBar, Set_toJSON)

Результат:

"{"foo":[1,2,3],"bar":[4,5,6]}"
tanguy_k
источник
6
в ES6 есть сокращенная версияJSON.stringify(fooBar, (key, value) => value instanceof Set ? [...value] : value)
OzzyCzech
Соответствующий оживитель оставлен в качестве упражнения для читателя? ;-)
Роберт Симер
9

Хотя все вышеперечисленное работает, я предлагаю вам создать подклассы и добавить toJSONметод, чтобы убедиться, что он правильно структурирует. Особенно, если вы собираетесь часто натягивать струны. Я использую наборы в своих магазинах Redux, и мне нужно было убедиться, что это никогда не проблема.

Это базовая реализация. Именование просто для того, чтобы проиллюстрировать ваш собственный стиль.

class JSONSet extends Set {
    toJSON () {
        return [...this]
    }
}

const set = new JSONSet([1, 2, 3])
console.log(JSON.stringify(set))
Стивен Болтон
источник
4
Я бы не рекомендовал этот подход, поскольку toJSONон считается устаревшей функцией. Предложение добавить toJSONк обоим setи mapбыло отклонено: github.com/DavidBruant/Map-Set.prototype.toJSON/issues/16
MitMaro
Переопределение constructorне требуется.
Джастин Джонсон