From eb9692a96ef071f6a0e04ae09d048569588b0a35 Mon Sep 17 00:00:00 2001 From: Vitalii Perehonchuk Date: Thu, 21 Mar 2024 13:28:08 +0200 Subject: [PATCH 1/2] update(JS): web/javascript/reference/global_objects/json --- .../reference/global_objects/json/index.md | 85 +++++++++++++++++++ 1 file changed, 85 insertions(+) diff --git a/files/uk/web/javascript/reference/global_objects/json/index.md b/files/uk/web/javascript/reference/global_objects/json/index.md index 94e80093ae..9756637b78 100644 --- a/files/uk/web/javascript/reference/global_objects/json/index.md +++ b/files/uk/web/javascript/reference/global_objects/json/index.md @@ -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, що відповідає переданому значенню, необов'язково включаючи лише певні властивості або замінюючи значення властивостей у спосіб, визначений користувачем. @@ -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 + +Якщо система-одержувач не має таких же можливостей обробки JSON, як JavaScript, і не підтримує числа високої точності, можна серіалізувати число як рядок, а потім обробити його як рядок на стороні одержувача. Також цей варіант є єдиним можливим у старих версіях JavaScript. + +Щоб задати те, як власні типи даних (в тому числі `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. + +При розбиранні 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}} From 37c6eb1c507c502994c072dc7f6a8869304ba86b Mon Sep 17 00:00:00 2001 From: Vitalii Perehonchuk Date: Fri, 12 Apr 2024 12:53:56 +0300 Subject: [PATCH 2/2] update(JS): web/javascript/reference/global_objects/json --- .../uk/web/javascript/reference/global_objects/json/index.md | 4 ++-- uk_spelling_additions.txt | 2 ++ 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/files/uk/web/javascript/reference/global_objects/json/index.md b/files/uk/web/javascript/reference/global_objects/json/index.md index 9756637b78..da5d5d4b77 100644 --- a/files/uk/web/javascript/reference/global_objects/json/index.md +++ b/files/uk/web/javascript/reference/global_objects/json/index.md @@ -94,11 +94,11 @@ DIGIT = %x30-39 ; 0-9 ## Статичні методи -- {{jsxref("JSON.isRawJSON()")}} +- {{jsxref("JSON.isRawJSON()")}} {{experimental_inline}} - : Перевіряє, чи є значення об'єктом, поверненим {{jsxref("JSON.rawJSON()")}}. - {{jsxref("JSON.parse()")}} - : Розібрати порцію рядкового тексту як JSON, необов'язково перетворюючи отримане значення та його властивості, і повернути значення. -- {{jsxref("JSON.rawJSON()")}} +- {{jsxref("JSON.rawJSON()")}} {{experimental_inline}} - : Створює об'єкт "необробленого JSON", що вміщає уривок тексту JSON. При серіалізації в JSON об'єкт необробленого JSON тлумачиться як вже готовий уривок JSON. Цей текст повинен бути дійсним JSON. - {{jsxref("JSON.stringify()")}} - : Повернути рядок JSON, що відповідає переданому значенню, необов'язково включаючи лише певні властивості або замінюючи значення властивостей у спосіб, визначений користувачем. diff --git a/uk_spelling_additions.txt b/uk_spelling_additions.txt index ec8153bfcf..130d9047cf 100644 --- a/uk_spelling_additions.txt +++ b/uk_spelling_additions.txt @@ -405,6 +405,8 @@ сетери сетерів синдикації +система-одержувач +системи-одержувача співвикористанням співпрограми спрайтових