diff --git a/1-js/05-data-types/12-json/1-serialize-object/task.md b/1-js/05-data-types/12-json/1-serialize-object/task.md index 4d5a9d08a..8c5dd3a30 100644 --- a/1-js/05-data-types/12-json/1-serialize-object/task.md +++ b/1-js/05-data-types/12-json/1-serialize-object/task.md @@ -4,7 +4,7 @@ importance: 5 # Перетворіть об’єкт в JSON і назад -Перетворіть `user` в JSON, а потім перетворіть його назад в іншу змінну. +Перетворіть `user` на JSON, після цього зробіть з нього знову об'єкт і запишіть його в іншу змінну. ```js let user = { diff --git a/1-js/05-data-types/12-json/2-serialize-event-circular/task.md b/1-js/05-data-types/12-json/2-serialize-event-circular/task.md index 4627c2989..1664e65a9 100644 --- a/1-js/05-data-types/12-json/2-serialize-event-circular/task.md +++ b/1-js/05-data-types/12-json/2-serialize-event-circular/task.md @@ -6,7 +6,7 @@ importance: 5 У простих випадках циклічних посиланнь ми можемо виключити від серіалізації властивість, через яку воно виникло, за її ім’ям. -Але іноді ми не можемо просто використовувати назву, оскільки вона може використовуватися як і у циклічних посиланнях, так і в нормальних властивостях. Таким чином, ми можемо перевірити властивість за її значенням. +Але іноді ми не можемо просто використовувати назву, оскільки вона може використовуватися як і у циклічних посиланнях, так і в звичайних, потрібних нам, властивостях. Таким чином, ми можемо перевірити властивість за її значенням. Напишіть функцію `replacer`, щоб серіалізувати все, але видалити властивості, які посилаються на `meetup`: diff --git a/1-js/05-data-types/12-json/article.md b/1-js/05-data-types/12-json/article.md index e24aaabb1..1599f3721 100644 --- a/1-js/05-data-types/12-json/article.md +++ b/1-js/05-data-types/12-json/article.md @@ -1,10 +1,10 @@ # Методи JSON, toJSON -Скажімо, у нас є складний об’єкт, і ми хотіли б перетворити його в рядок, щоб відправити його через мережу або просто вивести його для цілей логування. +Скажімо, у нас є складний об’єкт, і ми хотіли б перетворити його в рядок, щоб відправити його через мережу або просто вивести його для логування. Безумовно, такий рядок повинен включати всі важливі властивості. -Ми могли б реалізувати перетворення, наступним чином: +Ми могли б реалізувати перетворення наступним чином: ```js run let user = { @@ -21,20 +21,20 @@ let user = { alert(user); // {name: "Іван", age: 30} ``` -... Але в процесі розробки додаються нові властивості, старі властивості перейменовуються та видаляються. Оновлення такого `toString` кожен раз може стати проблемою. Ми могли б спробувати проходити в циклі над властивостями в об’єкті, але що, якщо об’єкт є складним і має вкладені об’єкти у властивостях? Ми також повинні реалізувати їх перетворення. +... Але в процесі розробки додаються нові властивості, старі властивості перейменовуються та видаляються. Оновлення такого `toString` кожен раз може стати проблемою. Ми могли б спробувати перебрати властивості в ньому, але що, якщо об’єкт є складним і в його властивостях є вкладені об’єкти? Ми також повинні реалізувати їх перетворення. -На щастя, нема потреби писати код для обробки всього цього. Завдання вже вирішено. +На щастя, нема потреби писати код для обробки всього цього. У цьго завдання є просте рішення. ## JSON.stringify -[JSON](https://uk.wikipedia.org/wiki/JSON) (JavaScript Object Notation) -- це загальний формат, який представляє значення та об’єкти. Він описується у [стандарті RFC 4627](https://datatracker.ietf.org/doc/html/rfc4627). Спочатку він був розроблений для JavaScript, але багато інших мов мають бібліотеки, щоб обробляють його також. Тому легко використовувати JSON для обміну даними, коли клієнт використовує JavaScript, а сервер написаний на Ruby/PHP/Java тощо. +[JSON](https://uk.wikipedia.org/wiki/JSON) (JavaScript Object Notation) -- це загальний формат, який представляє значення та об’єкти. Він описується у [стандарті RFC 4627](https://datatracker.ietf.org/doc/html/rfc4627). Спочатку він був розроблений для JavaScript, але багато інших мов мають бібліотеки, для його обробки. Тому легко використовувати JSON для обміну даними, коли клієнт використовує JavaScript, а сервер написаний на Ruby/PHP/Java тощо. JavaScript надає методи: -- `JSON.stringify` для перетворення об’єктів в JSON (у вигляді тексту). -- `JSON.parse` для перетворення JSON-тексту назад в об’єкт. +- `JSON.stringify` для перетворення об’єктів в JSON (він повертає JSON-рядок). +- `JSON.parse` для перетворення JSON-рядка назад в об’єкт. -Наприклад, тут ми викликаємо `JSON.stringify` з об’єктом `student`: +Наприклад, тут ми трансформуємо дані студента за домогою `JSON.stringify`: ```js run let student = { name: 'Іван', @@ -66,13 +66,12 @@ alert(json); Метод `JSON.stringify(student)` бере об’єкт і перетворює його в рядок. -Отриманий `json` рядок називається *JSON-кодованим* або *серіалізованим* об’єктом. Ми готові відправити його по мережі або покласти в просте сховище даних. - +Отриманий `json` рядок називається *JSON-кодованим* або *серіалізованим* об’єктом. Ми готові відправити його по мережі або покласти в звичайне сховище даних. Будь ласка, зверніть увагу, що JSON-кодований об’єкт має кілька важливих відмінностей від літерального об’єкта: -- Рядки використовують подвійні лапки. Немає одиничних або зворотніх лапок у JSON. Отже, `'Іван'` стає `"Іван"`. -- Назви властивостей об’єкта також обертаються в подвійні лапки. Це обов’язково. Отже, `age:30` стає `"age":30`. +- Рядки використовують подвійні лапки. Ніяких одинарних або зворотніх лапок у JSON. Тобто `'Іван'` стає `"Іван"`. +- Назви властивостей об’єкта також обертаються в подвійні лапки. Це обов’язково. Тобто `age:30` стає `"age":30`. `JSON.stringify` можна застосувати до примітивів. @@ -83,7 +82,7 @@ JSON підтримує наступні типи даних: - Примітиви: - рядки, - числа, - - бульові значення `true/false`, + - логічні значення `true/false`, - `null`. Наприклад: @@ -100,18 +99,18 @@ alert( JSON.stringify(true) ); // true alert( JSON.stringify([1, 2, 3]) ); // [1,2,3] ``` -JSON -- це лише незалежна специфікація даних, тому деякі притаманні для JavaScript властивості об’єктів пропускаються в `JSON.stringify`. +JSON -- незалежна від мови специфікація даних, тому `JSON.stringify` пропускає деякі специфічні для JavaScript властивості об’єктів. А саме: - Функціональні властивості (методи). - Символьні ключі та значення. -- Властивості, що зберігають `undefined`. +- Властивості, що мають `undefined`. ```js run let user = { sayHi() { // ігнорується - alert("Hello"); + alert("Привіт"); }, [Symbol("id")]: 123, // ігнорується something: undefined // ігнорується @@ -138,7 +137,7 @@ let meetup = { }; alert( JSON.stringify(meetup) ); -/* Вся структура серіалізується: +/* Вся структура перетворена на рядок: { "title":"Конференція", "room":{"number":23,"participants":["Іван","Анна"]}, @@ -173,7 +172,7 @@ JSON.stringify(meetup); // Помилка: Конвертування циклі ![](json-meetup.svg) -## За винятком та трансформацією: Замінник +## За винятком та трансформацією: replacer Повний синтаксис `JSON.stringify`: @@ -190,7 +189,7 @@ replacer space : Кількість пробілів для форматування -Зазвичай, `JSON.stringify` використовується лише з першим аргументом. Але якщо нам потрібно добре налаштувати процес заміни, наприклад, якщо ми хочемо відфільтрувати циклічні посилання, то ми можемо використовувати другий аргумент `JSON.stringify`. +Зазвичай, `JSON.stringify` використовується лише з першим аргументом. Але якщо нам потрібно налаштувати процес заміни, наприклад, відфільтрувати циклічні посилання, то ми можемо використовувати другий аргумент `JSON.stringify`. Якщо ми передаємо йому масив властивостей, то будуть закодовані лише ці властивості. @@ -213,9 +212,9 @@ alert( JSON.stringify(meetup, *!*['title', 'participants']*/!*) ); // {"title":"Конференція","participants":[{},{}]} ``` -Тут ми, мабуть, занадто суворі. Список властивостей застосовується до всієї структури об’єкта. Отже, об’єкти в `participants` будуть порожніми, тому що `name` не в списку. +Тут ми, мабуть, занадто суворі. Список властивостей застосовується до всієї структури об’єкта. Тому об’єкти в `participants` будуть порожніми, бо `name` немає в списку. -Включімо в список кожної власності, крім `room.occupiedBy`, що призведе до циклічного посилання: +Включімо в список всі властивості, окрім `room.occupiedBy`, яка призводить до циклічного посилання: ```js run let room = { @@ -242,9 +241,9 @@ alert( JSON.stringify(meetup, *!*['title', 'participants', 'place', 'name', 'num Тепер все, крім `occupiedBy`, серіалізується. Але список властивостей досить довгий. -На щастя, ми можемо використовувати функцію замість масиву, в якості `replacer`. +На щастя, в якості `replacer` ми можемо використовувати функцію замість масиву. -Функція буде викликана для кожного `(key, value)`, і повинна повернути значення "replaced", яке буде використовуватися замість оригінального. Або `undefined`, якщо значення буде пропущено. +Функція буде викликана для кожного `(key, value)`, і повинна повернути замінене значення, яке буде використовуватися замість оригінального. Або `undefined`, якщо значення буде пропущено. У нашому випадку ми можемо повернути `value` "як є" для всього, крім `occupiedBy`. Щоб ігнорувати `occupiedBy`, код нижче повертає `undefined`: @@ -276,18 +275,18 @@ name: Іван name: Аліна place: [object Object] number: 23 -occupiedBy: [object Object] +occupiedBy: [object Object] */ ``` -Будь ласка, зверніть увагу, що функція `replacer` отримує кожну пару ключ/значення, включаючи вкладені об’єкти та елементи масиву. Він застосовується рекурсивно. Значення `this` всередині `replacer` -- це об’єкт, який містить поточну властивість. +Будь ласка, зверніть увагу, що функція `replacer` отримує кожну пару ключ/значення, включаючи вкладені об’єкти та елементи масиву. І вона застосовується рекурсивно. Значення `this` всередині `replacer` -- це об’єкт, який містить поточну властивість. -Перший виклик особливий. Він зроблений з використанням спеціального "об’єкта обгортки": `{"": meetup}`. Іншими словами, перша пара `(key, value)` має порожній ключ, а значення є цільовим об’єктом загалом. Ось чому перший рядок -- `":[object Object]"` в прикладі вище. +Перший виклик особливий. Він зроблений з використанням спеціального "об’єкта обгортки": `{"": meetup}`. Іншими словами, перша пара `(key, value)` має порожній ключ, а значення є цільовим об’єктом загалом. Ось чому перший рядок в прикладі вище буде `":[object Object]"` . -Ідея полягає в тому, щоб забезпечити якомога більше потужності для функції `replacer`: вона має можливість аналізувати та замінити/пропустити навіть весь об’єкт, якщо це необхідно. +Ідея полягає в тому, щоб забезпечити якомога більше можливостей для функції `replacer` -- вона має можливість аналізувати та замінити/пропустити навіть весь об’єкт, якщо це необхідно. -## Форматування: пробіл +## Форматування: space Третій аргумент `JSON.stringify(value, replacer, space)` -- це кількість пробілів, що використовуються для гарного форматування. @@ -329,13 +328,13 @@ alert(JSON.stringify(user, null, 2)); */ ``` -Третій аргумент також може бути рядок. У цьому випадку рядок використовується для відступу замість числа пробілів. +Третій аргумент також може бути рядок. У цьому випадку рядок використовується для відступу замість ряда пробілів. Параметр `space` використовується виключно для логування та гарного виводу. ## Спеціальний "toJSON" -Подібно до методу `toString` (для перетворення об’єкта в рядок), об’єкт також має метод `toJSON` для його перетворення в JSON. Функція `JSON.stringify` автоматично викликає цей метод. +Подібно до методу `toString` для перетворення в рядок, об’єкт також може мати метод `toJSON` для перетворення в JSON. Функція `JSON.stringify` автоматично викликає цей метод, якщо він є. Наприклад: @@ -362,9 +361,9 @@ alert( JSON.stringify(meetup) ); */ ``` -Тут ми бачимо, що `date` `(1)` став рядком. Це тому, що всі дати мають вбудований метод `toJSON`, який повертає такий рядок в такому вигляді. +Тут ми бачимо, що `date` `(1)` став рядком. Це тому, що всі об’єкти типу `Date` мають вбудований метод `toJSON`, який повертає такий рядок. -Тепер додаймо спеціальний `toJSON` для нашого об’єкта `room` `(2)`: +Тепер додамо власну реалізацію методу `toJSON` в наш об’єкт `room` `(2)`: ```js run let room = { @@ -396,7 +395,7 @@ alert( JSON.stringify(meetup) ); */ ``` -Як бачимо, `toJSON` використовується як для прямого виклику `JSON.stringify(room)`, а також коли властивість `room` вкладена в іншому закодованому об’єкті. +Як ми можемо побачити, `toJSON` використовується як при прямому виклику `JSON.stringify(room)`, так і коли `room` вкладений в іншому серіалізованому об’єкті. ## JSON.parse @@ -453,20 +452,20 @@ let json = `{ Існує інший формат, який називається [JSON5](http://json5.org/), що підтримує ключі не обернені в лапки, коментарі тощо. Але це окрема бібліотека, а не частина специфікації мови. -Звичайний JSON є настільки строгим не тому, що її розробники ледачі, а тому, що дозволяє легко, надійно та дуже швидко реалізувати алгоритм кодування та читання. +Звичайний JSON є настільки строгим не тому, що його розробники ледачі, а тому, що дозволяє легко, надійно та дуже швидко реалізувати алгоритм кодування та читання. -## Використання функції відновлення +## Використання reviver Уявіть, що ми отримали серіалізований об’єкт `meetup` з сервера. -Це виглядає так: +Ось такий: ```js // title: (meetup title), date: (meetup date) let str = '{"title":"Конференція","date":"2017-11-30T12:00:00.000Z"}'; ``` -...І тепер нам потрібно *десеріалізувати* цей об’єкт, щоб перетворити його в об’єкт JavaScript. +...І тепер нам потрібно *десеріалізувати* цей об’єкт, тобто знову перетворити його в об’єкт JavaScript. Зробімо це, викликавши `JSON.parse`: @@ -482,7 +481,7 @@ alert( meetup.date.getDate() ); // Помилка! Ой! Помилка! -Значення `meetup.date` -- це рядок, а не об’єкт `Date`. Як `JSON.parse` знає, що він повинен перетворити цей рядок на об’єкт `Date`? +Значення `meetup.date` -- це рядок, а не об’єкт `Date`. Як `JSON.parse` міг знати, що він повинен перетворити цей рядок на об’єкт `Date`? Передаймо до `JSON.parse` функції відновлення як другий аргумент, який повертає всі значення "як є", але `date` стане об’єктом `Date`: diff --git a/1-js/05-data-types/12-json/json-meetup.svg b/1-js/05-data-types/12-json/json-meetup.svg index 3fa32a261..8aa15bd1f 100644 --- a/1-js/05-data-types/12-json/json-meetup.svg +++ b/1-js/05-data-types/12-json/json-meetup.svg @@ -1 +1 @@ -number: 23title: "Conference"...placeoccupiedByparticipants \ No newline at end of file +number: 23title: "Конференція"...placeoccupiedByparticipants \ No newline at end of file