diff --git a/1-js/04-object-basics/07-optional-chaining/article.md b/1-js/04-object-basics/07-optional-chaining/article.md index 9591dcd6c..8ca41de9c 100644 --- a/1-js/04-object-basics/07-optional-chaining/article.md +++ b/1-js/04-object-basics/07-optional-chaining/article.md @@ -1,42 +1,42 @@ -# Optional chaining '?.' +# Опціональний ланцюжок '?.' [recent browser="new"] -The optional chaining `?.` is a safe way to access nested object properties, even if an intermediate property doesn't exist. +Опціональний ланцюжок `?.` -- це безпечний спосіб доступу до вкладених властивостей об’єктів, навіть якщо проміжних властивостей не існує. -## The "non-existing property" problem +## Проблема "відсутньої властивості" -If you've just started to read the tutorial and learn JavaScript, maybe the problem hasn't touched you yet, but it's quite common. +Якщо ви тільки почали читати підручник і вивчати JavaScript, можливо ця проблема вам наразі незнайома, проте вона достатньо розповсюджена. -As an example, let's say we have `user` objects that hold the information about our users. +Наприклад, розглянемо об’єкт `user` який містить інформацію про наших користувачів. -Most of our users have addresses in `user.address` property, with the street `user.address.street`, but some did not provide them. +В більшості наших користувачів є адреса `user.address` з вулицею `user.address.street`, проте дехто вирішив взагалі не вказувати адресу. -In such case, when we attempt to get `user.address.street`, and the user happens to be without an address, we get an error: +Отож якщо користувач не вказав адресу, а ми своєю чергою спробуємо отримати доступ до властивості `user.address.street`, то отримаємо помилку. ```js run -let user = {}; // a user without "address" property +let user = {}; // користувач без властивості "address" -alert(user.address.street); // Error! +alert(user.address.street); // помилка! ``` -That's the expected result. JavaScript works like this. As `user.address` is `undefined`, an attempt to get `user.address.street` fails with an error. +Це очікуваний розвиток подій, так працює JavaScript. Оскільки `user.address` є `undefined`, то і спроба отримати `user.address.street` закінчується помилкою. -In many practical cases we'd prefer to get `undefined` instead of an error here (meaning "no street"). +Проте в багатьох життєвих ситуаціях було б набагато зручніше просто отримати `undefined`, що буде означати "немає вулиці". -...And another example. In the web development, we can get an object that corresponds to a web page element using a special method call, such as `document.querySelector('.elem')`, and it returns `null` when there's no such element. +Ще один приклад. У веброзробці ми можемо отримати об’єкт котрий відповідає елементу на вебсторінці за допомогою спеціальних методів, наприклад: `document.querySelector('.elem')`. Проте якщо ми намагатимемось отримати елемент, якого немає на сторінці, то нам вернеться `null`. ```js run -// document.querySelector('.elem') is null if there's no element -let html = document.querySelector('.elem').innerHTML; // error if it's null +// document.querySelector('.elem') рівний null якщо такого елемента не існує +let html = document.querySelector('.elem').innerHTML; // помилка оскільки null ``` -Once again, if the element doesn't exist, we'll get an error accessing `.innerHTML` of `null`. And in some cases, when the absence of the element is normal, we'd like to avoid the error and just accept `html = null` as the result. +Для закріплення. Якщо елемента немає на вебсторінці, ми отримаємо помилку при спробі доступитися до властивості `.innerHTML`, оскільки при спробі його знайти ми отримаємо `null`. І в деяких випадках, коли відсутність елемента для нас є нормою, ми хотіли б просто отримати `.innerHTML = null` (тобто `html = null`). -How can we do this? +Як ми можемо це реалізувати? -The obvious solution would be to check the value using `if` or the conditional operator `?`, before accessing its property, like this: +Найочевиднішим рішенням було б перевірити властивість використавши `if` або за допомогою умовного оператора `?`: ```js let user = {}; @@ -44,55 +44,55 @@ let user = {}; alert(user.address ? user.address.street : undefined); ``` -It works, there's no error... But it's quite inelegant. As you can see, the `"user.address"` appears twice in the code. For more deeply nested properties, that becomes a problem as more repetitions are required. +Варіант робочий, помилки не буде... Але виглядає це вкрай неелегантно. Як ви бачите `"user.address"` двічі з’являється в коді. Для властивостей які лежать глибше, це стає проблемою оскільки потребує більшого дублювання. -E.g. let's try getting `user.address.street.name`. +Спробуймо отримати доступ до `user.address.street.name`. -We need to check both `user.address` and `user.address.street`: +Нам потрібно перевірити дві властивості `user.address` і `user.address.street`: ```js -let user = {}; // user has no address +let user = {}; // користувач без властивості "address" alert(user.address ? user.address.street ? user.address.street.name : null : null); ``` -That's just awful, one may even have problems understanding such code. +Виглядає просто жахливо і нечитабельно -Don't even care to, as there's a better way to write it, using the `&&` operator: +Але не хвилюйтесь, існує кращий варіант реалізації такої задачі за допомогою логічного оператора `&&`: ```js run -let user = {}; // user has no address +let user = {}; // користувач без властивості "address" -alert( user.address && user.address.street && user.address.street.name ); // undefined (no error) +alert( user.address && user.address.street && user.address.street.name ); // undefined (немає помилки) ``` -AND'ing the whole path to the property ensures that all components exist (if not, the evaluation stops), but also isn't ideal. +Логічне "І" з ланцюжком властивостей гарантує нам, що всі вони існують (якщо ж ні -- обчислення припиняється), але й це все ще не ідеал. -As you can see, property names are still duplicated in the code. E.g. in the code above, `user.address` appears three times. +Як ви бачите, імена властивостей досі дублюються в коді. В прикладі вище властивість `user.address` появляється тричі. -That's why the optional chaining `?.` was added to the language. To solve this problem once and for all! +Ось чому опціональний ланцюжок `?.` був доданий в мову. Щоб вирішити цю проблему раз і назавжди! -## Optional chaining +## Опціональний ланцюжок -The optional chaining `?.` stops the evaluation if the value before `?.` is `undefined` or `null` and returns `undefined`. +Опціональний ланцюжок `?.` припиняє обчислення, якщо значення перед `?.` є `undefined` або `null`, і повертає `undefined`. -**Further in this article, for brevity, we'll be saying that something "exists" if it's not `null` and not `undefined`.** +**Для стислості надалі в цій статті ми будемо говорити про значення, що воно "існує", якщо воно відрізняється від `null` чи `undefined`** -In other words, `value?.prop`: -- works as `value.prop`, if `value` exists, -- otherwise (when `value` is `undefined/null`) it returns `undefined`. +Іншими словами, `value?.prop`: +- працює як `value.prop`, якщо `value` існує, +- інакше (коли `value` є `undefined/null`) воно повертає `undefined`. -Here's the safe way to access `user.address.street` using `?.`: +Ось безпечний спосіб доступитись до властивості `user.address.street` за допомогою `?.`: ```js run -let user = {}; // user has no address +let user = {}; // користувач без властивості "address" -alert( user?.address?.street ); // undefined (no error) +alert( user?.address?.street ); // undefined (немає помилки) ``` -The code is short and clean, there's no duplication at all. +Такий код виглядає коротшим і чистішим, взагалі немає ніякого дублювання. -Reading the address with `user?.address` works even if `user` object doesn't exist: +Читання властивості "address" з `user?.address` спрацює навіть коли в змінній `user` зберігається зовсім не об’єкт: ```js run let user = null; @@ -101,120 +101,120 @@ alert( user?.address ); // undefined alert( user?.address.street ); // undefined ``` -Please note: the `?.` syntax makes optional the value before it, but not any further. +Зверніть увагу, що синтаксис `?.` робить необов’язковою тільки властивість перед ним, а не будь-яку наступну. -E.g. in `user?.address.street.name` the `?.` allows `user` to safely be `null/undefined` (and returns `undefined` in that case), but that's only for `user`. Further properties are accessed in a regular way. If we want some of them to be optional, then we'll need to replace more `.` with `?.`. +Наприклад в `user?.address.street.name` конструкція `user?.` дозволяє `user` залишатись `null/undefined` (і повертати `undefined` в такому випадку), але це працює тільки для `user`. Доступ до решти властивостей здійснюється звичайним способом. Якщо ми хочемо, щоб якась з них була необов’язковою, тоді конкретно для цієї властивості нам доведеться замінити `.` на `?.`. -```warn header="Don't overuse the optional chaining" -We should use `?.` only where it's ok that something doesn't exist. +````warn header="Не зловживайте опціональним ланцюжком" +Нам слід використовувати `?.` тільки в тих ситуаціях коли ми припускаємо що значення може не існувати. -For example, if according to our coding logic `user` object must exist, but `address` is optional, then we should write `user.address?.street`, but not `user?.address?.street`. +Наприклад, якщо по нашій логіці об’єкт `user` точно існує, але його властивість `address` є необов’язковою, тоді нам слід використовувати конструкцію `user.address?.street`. Проте аж ніяк не `user?.address?.street`. -So, if `user` happens to be undefined due to a mistake, we'll see a programming error about it and fix it. Otherwise, coding errors can be silenced where not appropriate, and become more difficult to debug. -``` +Тоді якщо помилково змінна `user` виявиться пустою, ми побачимо програмну помилку і зможемо це виправити. В іншому випадку помилки можуть замовчуватися там де це непотрібно й ускладнювати процес налагодження. +```` -````warn header="The variable before `?.` must be declared" -If there's no variable `user` at all, then `user?.anything` triggers an error: +````warn header="Змінна перед `?.` повинна бути оголошеною" +Якщо змінної `user` взагалі не існує, тоді конструкція `user?.anything` видасть помилку: ```js run // ReferenceError: user is not defined user?.address; ``` -The variable must be declared (e.g. `let/const/var user` or as a function parameter). The optional chaining works only for declared variables. +Змінна обов’язково повинна бути оголошена (наприклад `let/const/var user` або як параметр функції). Опціональний ланцюжок працює тільки з існуючими змінними. ```` -## Short-circuiting +## Скорочене обчислення -As it was said before, the `?.` immediately stops ("short-circuits") the evaluation if the left part doesn't exist. +Як вже говорилось, `?.` негайно припиняє обчислення, якщо лівої частини не існує. -So, if there are any further function calls or side effects, they don't occur. +Таким чином подальші виклики функцій чи операції не будуть виконані. -For instance: +Наприклад: ```js run let user = null; let x = 0; -user?.sayHi(x++); // no "sayHi", so the execution doesn't reach x++ +user?.sayHi(x++); // немає "sayHi", отже до x++ обчислення не дійде -alert(x); // 0, value not incremented +alert(x); // 0, значення не було збільшено ``` -## Other variants: ?.(), ?.[] +## Інші способи застосування: ?.(), ?.[] -The optional chaining `?.` is not an operator, but a special syntax construct, that also works with functions and square brackets. +Опціональний ланцюжок `?.` -- це не оператор, а спеціальна синтаксична конструкція, що також працює з функціями і квадратними дужками. -For example, `?.()` is used to call a function that may not exist. +Наприклад, `?.()` використовується для виклику потенційно неіснуючої функції. -In the code below, some of our users have `admin` method, and some don't: +В прикладі нижче не в усіх користувачів є метод `admin`: ```js run let userAdmin = { admin() { - alert("I am admin"); + alert("Я адміністратор"); } }; let userGuest = {}; *!* -userAdmin.admin?.(); // I am admin +userAdmin.admin?.(); // Я адміністратор */!* *!* -userGuest.admin?.(); // nothing (no such method) +userGuest.admin?.(); // нічого (немає такого методу) */!* ``` -Here, in both lines we first use the dot (`userAdmin.admin`) to get `admin` property, because we assume that the user object exists, so it's safe read from it. +В обох випадках спочатку використовуємо крапку (`userAdmin.admin`) для доступу до властивості `admin`, оскільки об’єкт користувача точно існує, а це означає що ми можемо звернутись до будь-якої його властивості на першому рівні вкладеності без помилки. -Then `?.()` checks the left part: if the admin function exists, then it runs (that's so for `userAdmin`). Otherwise (for `userGuest`) the evaluation stops without errors. +Вже потім `?.()` перевіряє ліву частину: якщо функція `admin` існує, то вона виконається (у випадку з `userAdmin`). Інакше (для `userGuest`) обчислення припиниться без помилок. -The `?.[]` syntax also works, if we'd like to use brackets `[]` to access properties instead of dot `.`. Similar to previous cases, it allows to safely read a property from an object that may not exist. +Також існує синтаксис `?.[]`, якщо ми хочемо отримати доступ до властивості за допомогою квадратних дужок `[]`, а не через крапку `.`. Як і в решті випадків, таких спосіб дає змогу безпечно читати властивості об’єкту яких може не існувати. ```js run let key = "firstName"; let user1 = { - firstName: "John" + firstName: "Іван" }; -let user2 = null; +let user2 = null; // уявімо, що користувач не авторизувався -alert( user1?.[key] ); // John +alert( user1?.[key] ); // Іван alert( user2?.[key] ); // undefined ``` -Also we can use `?.` with `delete`: +Ми також можемо використовувати `?.` з `delete`: ```js run -delete user?.name; // delete user.name if user exists +delete user?.name; // видалити user.name, якщо користувач існує ``` -````warn header="We can use `?.` for safe reading and deleting, but not writing" -The optional chaining `?.` has no use at the left side of an assignment. +````warn header="Ми можемо використовувати `?.` для безпечного читання і видалення властивостей, але не для запису" +Опціональний ланцюжок `?.` не має сенсу у лівій частині присвоювання. -For example: +Наприклад: ```js run let user = null; -user?.name = "John"; // Error, doesn't work -// because it evaluates to undefined = "John" +user?.name = "Іван"; // Помилка, не працює +// це по суті те ж саме що undefined = "John" ``` -It's just not that smart. +Воно недостатньо «розумне» для цього. ```` -## Summary +## Підсумки -The optional chaining `?.` syntax has three forms: +Синтаксис опціонального ланцюжка `?.` має три форми: -1. `obj?.prop` -- returns `obj.prop` if `obj` exists, otherwise `undefined`. -2. `obj?.[prop]` -- returns `obj[prop]` if `obj` exists, otherwise `undefined`. -3. `obj.method?.()` -- calls `obj.method()` if `obj.method` exists, otherwise returns `undefined`. +1. `obj?.prop` -- повертає `obj.prop`, якщо існує `obj`, і `undefined` в іншому випадку. +2. `obj?.[prop]` -- повертає `obj[prop]`, якщо існує `obj`, і `undefined` в іншому випадку. +3. `obj.method?.()` -- викликає `obj.method()`, якщо існує `obj.method`, в іншому випадку повертає `undefined`. -As we can see, all of them are straightforward and simple to use. The `?.` checks the left part for `null/undefined` and allows the evaluation to proceed if it's not so. +Як бачимо, всі вони прості та зрозумілі в використанні. `?.` перевіряє ліву частину на рівність `null/undefined` і дозволяє продовжувати обчислення якщо це не так. -A chain of `?.` allows to safely access nested properties. +Ланцюжок `?.` дозволяє без виникнення помилок звертатись до вкладених властивостей. -Still, we should apply `?.` carefully, only where it's acceptable that the left part doesn't exist. So that it won't hide programming errors from us, if they occur. +Тим не менш, потрібно розумно застосовувати `?.`, тільки в тих випадках де допустимо що ліва частина не існує. Щоб таким чином не приховувати потенційні помилки програмування. pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy