Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

update(JS): web/javascript/reference/global_objects/json #2901

Merged
Merged
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
85 changes: 85 additions & 0 deletions files/uk/web/javascript/reference/global_objects/json/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -94,8 +94,12 @@ DIGIT = %x30-39 ; 0-9

## Статичні методи

- {{jsxref("JSON.isRawJSON()")}}
- : Перевіряє, чи є значення об'єктом, поверненим {{jsxref("JSON.rawJSON()")}}.
- {{jsxref("JSON.parse()")}}
- : Розібрати порцію рядкового тексту як JSON, необов'язково перетворюючи отримане значення та його властивості, і повернути значення.
- {{jsxref("JSON.rawJSON()")}}
- : Створює об'єкт "необробленого JSON", що вміщає уривок тексту JSON. При серіалізації в JSON об'єкт необробленого JSON тлумачиться як вже готовий уривок JSON. Цей текст повинен бути дійсним JSON.
- {{jsxref("JSON.stringify()")}}
- : Повернути рядок JSON, що відповідає переданому значенню, необов'язково включаючи лише певні властивості або замінюючи значення властивостей у спосіб, визначений користувачем.

Expand Down Expand Up @@ -145,6 +149,87 @@ const jsonText = `{
console.log(JSON.parse(jsonText));
```

### Серіалізація чисел без втрат

JSON може вміщати числові літерали довільної точності. Однак не можна представити з повною точністю в JavaScript усі числа JSON, оскільки JavaScript використовує представлення з рухомою комою, яке має фіксовану точність. Наприклад, у JavaScript `12345678901234567890 === 12345678901234567000`, оскільки ці числа мають одне й те ж представлення з рухомою комою. Це означає, що в JavaScript немає числа, яке точно відповідало б числу JSON `12345678901234567890`.

Припустімо, що є точне представлення деякого числа (чи то через {{jsxref("BigInt")}}, чи через власну бібліотеку):

```js
const data = {
// Тут для зберігання точного значення використовується BigInt,
// але можна використовувати також власну бібліотеку чисел високої точності,
// якщо число може бути не цілим.
gross_gdp: 12345678901234567890n,
};
```

Є потреба його серіалізувати, а потім розібрати на точно те саме число. Є кілька складнощів:

- З боку серіалізації, щоб отримати число в JSON, необхідно передати в `JSON.stringify` саме число, або через функцію `replacer`, або через метод `toJSON`. Але в обох випадках точність втрачається вже під час перетворення цього числа. Якщо передати рядок в `JSON.stringify`, він буде серіалізований як рядок, а не як число.
- З боку розбору, не всі числа можна представити точним чином. Наприклад, `JSON.parse("12345678901234567890")` повертає `12345678901234568000`, оскільки число округлюється до найближчого числа, яке можна представити. Навіть якщо скористатися функцією `reviver`, число вже буде округлене до відповідного числа до того, як функція `reviver` буде викликана.

Загалом, є два способи забезпечити перетворення чисел у JSON і розбір назад без втрат: один з них залучає число JSON, а інший – рядок JSON. JSON – це _комунікаційний формат_, тож якщо використовується JSON, то, ймовірно, відбувається комунікація з іншою системою (запит HTTP, збереження у базі даних тощо). Найкраще рішення в конкретній ситуації залежить від системи-одержувача.

#### Використання рядків JSON
undead404 marked this conversation as resolved.
Show resolved Hide resolved

Якщо система-одержувач не має таких же можливостей обробки JSON, як JavaScript, і не підтримує числа високої точності, можна серіалізувати число як рядок, а потім обробити його як рядок на стороні одержувача. Також цей варіант є єдиним можливим у старих версіях JavaScript.
undead404 marked this conversation as resolved.
Show resolved Hide resolved

Щоб задати те, як власні типи даних (в тому числі `BigInt`) повинні бути серіалізовані в JSON, потрібно або додати до власного типу даних метод `toJSON`, або скористатися функцією `replacer` {{jsxref("JSON.stringify()")}}.

```js
// Використання методу toJSON()
BigInt.prototype.toJSON = function () {
return this.toString();
};
const str1 = JSON.stringify(data);

// Використання JSON.stringify() з замінювачем
const str2 = JSON.stringify(data, (key, value) => {
if (key === "gross_gdp") {
return value.toString();
}
return value;
});
```

В обох випадках текст JSON матиме вигляд `{"gross_gdp":"12345678901234567890"}`, де значення є рядком, а не числом. Потім на стороні одержувача можна розібрати JSON і обробити рядок.

#### Використання чисел JSON

Якщо одержувач повідомлення нативно підтримує числа високої точності (наприклад, цілі числа Python), передача чисел у вигляді чисел JSON, очевидно, є кращим підходом, адже тоді одержувач може безпосередньо розібрати їх у тип високої точності, а не розбирати рядок з JSON, а потім розбирати число з рядка. У JavaScript можна серіалізувати довільні типи даних у числа JSON без втрати точності, не створюючи спершу числове значення (що призвело б до втрати точності) шляхом використання {{jsxref("JSON.rawJSON()")}}, щоб точно вказати, яким має бути вихідний текст JSON.

```js
// Використання методу toJSON()
BigInt.prototype.toJSON = function () {
return JSON.rawJSON(this.toString());
};
const str1 = JSON.stringify(data);

// Використання JSON.stringify() з замінювачем
const str2 = JSON.stringify(data, (key, value) => {
if (key === "gross_gdp") {
return JSON.rawJSON(value.toString());
}
return value;
});
```

Текст, переданий до `JSON.rawJSON`, тлумачиться як вже готовий уривок JSON, тому він не буде серіалізований як рядок. Таким чином, текст JSON буде мати вигляд `{"gross_gdp":12345678901234567890}`, де значення є числом. Цей JSON одержувач може розібрати без будь-якої додаткової обробки, за умови того, що система-одержувач не має таких же обмежень точності, як JavaScript.
undead404 marked this conversation as resolved.
Show resolved Hide resolved

При розбиранні JSON, що містить числа високої точності, в JavaScript, слід дотримуватись особливої обережності, тому що коли `JSON.parse()` закликає функцію `reviver`, то отримане значення вже розібране (і вже втратило точність). Можна скористатися параметром `context.source` функції `reviver` {{jsxref("JSON.parse()")}}, щоб самостійно розібрати число заново.

```js
const parsedData = JSON.parse(str, (key, value, context) => {
if (key === "gross_gdp") {
// Або скористатися конструктором власної бібліотеки чисел високої точності
return BigInt(context.source);
}
return value;
});
// { gross_gdp: 12345678901234567890n }
```

## Специфікації

{{Specifications}}
Expand Down
Loading