Spec-Zone.ru › JavaScript

JSON.stringify()

Базовый уровень Широко доступно

Эта функция хорошо зарекомендовала себя и работает на многих устройствах и версиях браузеров. Она доступна во всех браузерах с июля 2015 года.

Статический метод JSON.stringify() преобразует значение JavaScript в строку JSON, опционально заменяя значения, если указана функция-заменитель (replacer), или опционально включая только указанные свойства, если указан массив-заменитель.

Попробовать

console.log(JSON.stringify({ x: 5, y: 6 }));
// Expected output: '{"x":5,"y":6}'

console.log(
  JSON.stringify([new Number(3), new String("false"), new Boolean(false)]),
);
// Expected output: '[3,"false",false]'

console.log(JSON.stringify({ x: [10, undefined, function () {}, Symbol("")] }));
// Expected output: '{"x":[10,null,null,null]}'

console.log(JSON.stringify(new Date(2006, 0, 2, 15, 4, 5)));
// Expected output: '"2006-01-02T15:04:05.000Z"'

Синтаксис

JSON.stringify(value)
JSON.stringify(value, replacer)
JSON.stringify(value, replacer, space)

Параметры

value
Значение для преобразования в строку JSON.
replacer Необязательно
Функция, изменяющая поведение процесса преобразования в строку (stringification), или массив строк и чисел, который указывает свойства value, которые должны быть включены в вывод. Если replacer является массивом, все элементы в этом массиве, которые не являются строками или числами (будь то примитивы или объекты-оболочки), включая значения Symbol, полностью игнорируются. Если replacer является чем-либо, кроме функции или массива (например, null или не предоставлен), все свойства объекта с ключами-строками включаются в результирующую строку JSON.
space Необязательно

Строка или число, используемое для вставки пробельных символов (включая отступы, символы перевода строки и т.д.) в выходную строку JSON для улучшения читаемости.

Если это число, оно указывает количество пробельных символов, которое будет использоваться в качестве отступа, ограниченное 10 (то есть любое число, большее 10, обрабатывается как 10). Значения меньше 1 указывают, что пробельные символы использоваться не должны.

Если это строка, эта строка (или первые 10 символов строки, если она длиннее) вставляется перед каждым вложенным объектом или массивом.

Если space является чем-либо, кроме строки или числа (может быть как примитивом, так и объектом-оболочкой) — например, является null или не предоставлен — пробельные символы не используются.

Возвращаемое значение

Строка JSON, представляющая заданное значение, или undefined.

Исключения

TypeError
Выбрасывается в одном из следующих случаев:
  • value содержит циклическую ссылку.
  • Обнаружено значение BigInt.

Описание

JSON.stringify() преобразует значение в нотацию JSON, которую оно представляет. Значения преобразуются в строку следующим образом:

  • Объекты Boolean, Number, String и BigInt (получаемые через Object()) преобразуются в соответствующие примитивные значения во время преобразования в строку, в соответствии с традиционной семантикой преобразования. Объекты Symbol (получаемые через Object()) обрабатываются как простые объекты.
  • Попытка сериализовать значения BigInt приведет к ошибке. Однако, если BigInt имеет метод toJSON() (через "обезьянье патчирование": BigInt.prototype.toJSON = ...), этот метод может предоставить результат сериализации. Это ограничение гарантирует, что надлежащее поведение сериализации (и, вероятно, сопровождающей ее десериализации) всегда явно предоставляется пользователем.
  • Значения undefined, Function и Symbol не являются допустимыми значениями JSON. Если какие-либо такие значения встречаются во время преобразования, они либо опускаются (если находятся в объекте), либо изменяются на null (если находятся в массиве). JSON.stringify() может вернуть undefined при передаче «чистых» значений, таких как JSON.stringify(() => {}) или JSON.stringify(undefined).
  • Числа Infinity и NaN, а также значение null, все считаются null. (Но в отличие от значений в предыдущем пункте, они никогда не будут опущены.)
  • Массивы сериализуются как массивы (заключенные в квадратные скобки). Сериализуются только индексы массива между 0 и length - 1 (включительно); другие свойства игнорируются.
  • Специальный "сырой" объект JSON, созданный с помощью JSON.rawJSON(), сериализуется как содержащийся в нем необработанный текст JSON (путем доступа к его свойству rawJSON).
  • Для других объектов:
    • Все свойства с ключами Symbol будут полностью проигнорированы, даже при использовании параметра replacer.

    • Если значение имеет метод toJSON(), он отвечает за определение того, какие данные будут сериализованы. Вместо сериализации объекта будет сериализовано значение, возвращаемое методом toJSON() при вызове. JSON.stringify() вызывает toJSON с одним параметром, key, который имеет ту же семантику, что и параметр key функции replacer:
      • если этот объект является значением свойства, то имя свойства
      • если он находится в массиве, то индекс в массиве в виде строки
      • если JSON.stringify() был вызван непосредственно для этого объекта, то пустая строка

      Все объекты Temporal реализуют метод toJSON(), который возвращает строку (то же самое, что и вызов toString()). Таким образом, они будут сериализованы как строки. Аналогично, объекты Date реализуют toJSON(), который возвращает то же самое, что и toISOString().

    • Посещаются только перечисляемые собственные свойства. Это означает, что Map, Set и т. д. станут "{}". Вы можете использовать параметр replacer для их сериализации во что-то более полезное.

      Свойства посещаются с использованием того же алгоритма, что и в Object.keys(), который имеет четко определенный порядок и стабилен для разных реализаций. Например, JSON.stringify для одного и того же объекта всегда будет производить одну и ту же строку, а JSON.parse(JSON.stringify(obj)) будет производить объект с тем же порядком ключей, что и исходный (при условии, что объект полностью сериализуем в JSON).

Параметр replacer

Параметр replacer может быть либо функцией, либо массивом.

Как массив, его элементы указывают имена свойств в объекте, которые должны быть включены в результирующую строку JSON. Учитываются только строковые и числовые значения; символьные ключи игнорируются.

Как функция, она принимает два параметра: key и value, преобразуемое в строку. Объект, в котором был найден ключ, предоставляется как контекст this replacer.

Функция replacer также вызывается для исходного объекта, преобразуемого в строку, и в этом случае key является пустой строкой (""). Затем она вызывается для каждого свойства в преобразуемом объекте или массиве. Индексы массива будут предоставлены в строковой форме как key. Текущее значение свойства будет заменено возвращаемым значением replacer для преобразования в строку. Это означает:

  • Если вы возвращаете число, строку, логическое значение или null, это значение напрямую сериализуется и используется как значение свойства. (Возврат BigInt также вызовет ошибку.)
  • Если вы возвращаете Function, Symbol или undefined, свойство не включается в вывод.
  • Если вы возвращаете любой другой объект, этот объект рекурсивно преобразуется в строку, вызывая функцию replacer для каждого свойства.

Примечание: При разборе JSON, сгенерированного функциями replacer, вам, вероятно, потребуется использовать параметр reviver для выполнения обратной операции.

Обычно индекс элементов массива никогда не сдвигается (даже если элемент является недопустимым значением, например функцией, он станет null вместо того, чтобы быть опущенным). Использование функции replacer позволяет вам контролировать порядок элементов массива, возвращая другой массив.

Параметр space

Параметр space может использоваться для управления интервалами в итоговой строке.

  • Если это число, последовательные уровни при преобразовании в строку будут иметь отступ, равный этому числу пробельных символов.
  • Если это строка, последовательные уровни будут иметь отступ, равный этой строке.

Каждый уровень отступа никогда не будет длиннее 10. Числовые значения space ограничиваются 10, а строковые значения усекаются до 10 символов.

Примеры

Использование JSON.stringify

JSON.stringify({}); // '{}'
JSON.stringify(true); // 'true'
JSON.stringify("foo"); // '"foo"'
JSON.stringify([1, "false", false]); // '[1,"false",false]'
JSON.stringify([NaN, null, Infinity]); // '[null,null,null]'
JSON.stringify({ x: 5 }); // '{"x":5}'

JSON.stringify(new Date(1906, 0, 2, 15, 4, 5));
// '"1906-01-02T15:04:05.000Z"'

JSON.stringify({ x: 5, y: 6 });
// '{"x":5,"y":6}'
JSON.stringify([new Number(3), new String("false"), new Boolean(false)]);
// '[3,"false",false]'

// String-keyed array elements are not enumerable and make no sense in JSON
const a = ["foo", "bar"];
a["baz"] = "quux"; // a: [ 0: 'foo', 1: 'bar', baz: 'quux' ]
JSON.stringify(a);
// '["foo","bar"]'

JSON.stringify({ x: [10, undefined, function () {}, Symbol("")] });
// '{"x":[10,null,null,null]}'

// Standard data structures
JSON.stringify([
  new Set([1]),
  new Map([[1, 2]]),
  new WeakSet([{ a: 1 }]),
  new WeakMap([[{ a: 1 }, 2]]),
]);
// '[{},{},{},{}]'

// TypedArray
JSON.stringify([new Int8Array([1]), new Int16Array([1]), new Int32Array([1])]);
// '[{"0":1},{"0":1},{"0":1}]'
JSON.stringify([
  new Uint8Array([1]),
  new Uint8ClampedArray([1]),
  new Uint16Array([1]),
  new Uint32Array([1]),
]);
// '[{"0":1},{"0":1},{"0":1},{"0":1}]'
JSON.stringify([new Float32Array([1]), new Float64Array([1])]);
// '[{"0":1},{"0":1}]'

// toJSON()
JSON.stringify({
  x: 5,
  y: 6,
  toJSON() {
    return this.x + this.y;
  },
});
// '11'

// Symbols:
JSON.stringify({ x: undefined, y: Object, z: Symbol("") });
// '{}'
JSON.stringify({ [Symbol("foo")]: "foo" });
// '{}'
JSON.stringify({ [Symbol.for("foo")]: "foo" }, [Symbol.for("foo")]);
// '{}'
JSON.stringify({ [Symbol.for("foo")]: "foo" }, (k, v) => {
  if (typeof k === "symbol") {
    return "a symbol";
  }
});
// undefined

// Non-enumerable properties:
JSON.stringify(
  Object.create(null, {
    x: { value: "x", enumerable: false },
    y: { value: "y", enumerable: true },
  }),
);
// '{"y":"y"}'

// BigInt values throw
JSON.stringify({ x: 2n });
// TypeError: BigInt value can't be serialized in JSON

Использование функции в качестве replacer

function replacer(key, value) {
  // Filtering out properties
  if (typeof value === "string") {
    return undefined;
  }
  return value;
}

const foo = {
  foundation: "Mozilla",
  model: "box",
  week: 45,
  transport: "car",
  month: 7,
};
JSON.stringify(foo, replacer);
// '{"week":45,"month":7}'

Если вы хотите, чтобы replacer различал исходный объект и ключ с пустым строковым свойством (поскольку оба дадут пустую строку в качестве ключа и потенциально объект в качестве значения), вам придется отслеживать количество итераций (если это не первая итерация, это настоящий ключ с пустой строкой).

function makeReplacer() {
  let isInitial = true;

  return (key, value) => {
    if (isInitial) {
      isInitial = false;
      return value;
    }
    if (key === "") {
      // Omit all properties with name "" (except the initial object)
      return undefined;
    }
    return value;
  };
}

const replacer = makeReplacer();
console.log(JSON.stringify({ "": 1, b: 2 }, replacer)); // "{"b":2}"

Использование массива в качестве replacer

const foo = {
  foundation: "Mozilla",
  model: "box",
  week: 45,
  transport: "car",
  month: 7,
};

JSON.stringify(foo, ["week", "month"]);
// '{"week":45,"month":7}', only keep "week" and "month" properties

Использование параметра space

Отступ в выводе на один пробел:

console.log(JSON.stringify({ a: 2 }, null, " "));
/*
{
 "a": 2
}
*/

Использование символа табуляции имитирует стандартный вид "красивой" печати:

console.log(JSON.stringify({ uno: 1, dos: 2 }, null, "\t"));
/*
{
	"uno": 1,
	"dos": 2
}
*/

Поведение toJSON()

Определение toJSON() для объекта позволяет переопределить его поведение сериализации.

const obj = {
  data: "data",

  toJSON(key) {
    return key ? `Now I am a nested object under key '${key}'` : this;
  },
};

JSON.stringify(obj);
// '{"data":"data"}'

JSON.stringify({ obj });
// '{"obj":"Now I am a nested object under key 'obj'"}'

JSON.stringify([obj]);
// '["Now I am a nested object under key '0'"]'

Проблема с сериализацией циклических ссылок

Поскольку формат JSON не поддерживает ссылки на объекты (хотя существует черновик IETF), будет выброшена ошибка TypeError, если попытаться закодировать объект с циклическими ссылками.

const circularReference = {};
circularReference.myself = circularReference;

// Serializing circular references throws "TypeError: cyclic object value"
JSON.stringify(circularReference);

Чтобы сериализовать циклические ссылки, вы можете использовать библиотеку, которая их поддерживает (например, cycle.js Дугласа Крокфорда), или реализовать решение самостоятельно, что потребует поиска и замены (или удаления) циклических ссылок сериализуемыми значениями.

Если вы используете JSON.stringify() для глубокого копирования объекта, вы можете вместо этого использовать structuredClone(), который поддерживает циклические ссылки. API движка JavaScript для двоичной сериализации, такой как v8.serialize(), также поддерживают циклические ссылки.

Использование JSON.stringify() с localStorage

В случае, когда вы хотите сохранить объект, созданный пользователем, и обеспечить его восстановление даже после закрытия браузера, следующий пример является моделью применимости JSON.stringify():

// Creating an example of JSON
const session = {
  screens: [],
  state: true,
};
session.screens.push({ name: "screenA", width: 450, height: 250 });
session.screens.push({ name: "screenB", width: 650, height: 350 });
session.screens.push({ name: "screenC", width: 750, height: 120 });
session.screens.push({ name: "screenD", width: 250, height: 60 });
session.screens.push({ name: "screenE", width: 390, height: 120 });
session.screens.push({ name: "screenF", width: 1240, height: 650 });

// Converting the JSON string with JSON.stringify()
// then saving with localStorage in the name of session
localStorage.setItem("session", JSON.stringify(session));

// Example of how to transform the String generated through
// JSON.stringify() and saved in localStorage in JSON object again
const restoredSession = JSON.parse(localStorage.getItem("session"));

// Now restoredSession variable contains the object that was saved
// in localStorage
console.log(restoredSession);

Корректный JSON.stringify()

Движки, реализующие спецификацию корректного JSON.stringify, будут преобразовывать одиночные суррогаты (любая кодовая точка от U+D800 до U+DFFF) в строку с использованием управляющих последовательностей Unicode, а не буквально (выводя одиночные суррогаты). До этого изменения такие строки не могли быть закодированы в корректных UTF-8 или UTF-16:

JSON.stringify("\uD800"); // '"�"'

Но с этим изменением JSON.stringify() представляет одиночные суррогаты, используя управляющие последовательности JSON, которые могут быть закодированы в корректных UTF-8 или UTF-16:

JSON.stringify("\uD800"); // '"\\ud800"'

Это изменение должно быть обратно совместимым, если вы передаете результат JSON.stringify() в API, такие как JSON.parse(), которые принимают любой корректный текст JSON, поскольку они будут рассматривать управляющие последовательности Unicode для одиночных суррогатов как идентичные самим одиночным суррогатам. Только если вы напрямую интерпретируете результат JSON.stringify(), вам нужно осторожно обрабатывать две возможные кодировки этих кодовых точек в JSON.stringify().

Спецификации

Спецификация
ECMAScript® 2027 Language Specification
# sec-json.stringify

Совместимость с браузерами

Desktop Mobile Server
Chrome Edge Firefox Opera Safari Chrome Android Firefox for Android Opera Android Safari on iOS Samsung Internet WebView Android WebView on iOS Bun Deno Node.js
stringify
3
12
3.5
10.5
4
18
4
11
4
1.0
4.4
4
1.0.0
1.0
0.10.0
well_formed_stringify
72
79
64
60
12.1
72
64
50
12.2
11.0
72
12.2
1.0.0
1.0
12.0.0

Смотрите также

  • Полифилл современного поведения JSON.stringify (символ, корректный unicode, сырой JSON) в core-js
  • JSON.parse()
  • JSON.rawJSON()

© 2005–2025 MDN contributors.
Licensed under the Creative Commons Attribution-ShareAlike License v2.5 or later.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API