From d1bfa378fa5b8df7e053a079c223c84f4e1e832e Mon Sep 17 00:00:00 2001 From: Stanislav Dolgachov Date: Sun, 5 Dec 2021 23:52:00 +0200 Subject: [PATCH 1/9] 1-js/09-classes/06-instanceof: Translation --- .../1-strange-instanceof/solution.md | 8 +- .../1-strange-instanceof/task.md | 4 +- 1-js/09-classes/06-instanceof/article.md | 132 +++++++++--------- 3 files changed, 72 insertions(+), 72 deletions(-) diff --git a/1-js/09-classes/06-instanceof/1-strange-instanceof/solution.md b/1-js/09-classes/06-instanceof/1-strange-instanceof/solution.md index d41d90edf..bae631a3f 100644 --- a/1-js/09-classes/06-instanceof/1-strange-instanceof/solution.md +++ b/1-js/09-classes/06-instanceof/1-strange-instanceof/solution.md @@ -1,7 +1,7 @@ -Yeah, looks strange indeed. +Так, виглядає справді дивно. -But `instanceof` does not care about the function, but rather about its `prototype`, that it matches against the prototype chain. +Але `instanceof` нема діла до функції, все залежить від її властивості `prototype`, значення якої порівнюється з ланцюжком прототипів. -And here `a.__proto__ == B.prototype`, so `instanceof` returns `true`. +І тут `a.__proto__ == B.prototype`, тому `instanceof` повертає `true`. -So, by the logic of `instanceof`, the `prototype` actually defines the type, not the constructor function. +Отже, за логікою `instanceof`, властивість `prototype` насправді визначає тип, а не сама функція-конструктор. diff --git a/1-js/09-classes/06-instanceof/1-strange-instanceof/task.md b/1-js/09-classes/06-instanceof/1-strange-instanceof/task.md index 5b8dc7de3..bf3000ed3 100644 --- a/1-js/09-classes/06-instanceof/1-strange-instanceof/task.md +++ b/1-js/09-classes/06-instanceof/1-strange-instanceof/task.md @@ -2,9 +2,9 @@ importance: 5 --- -# Strange instanceof +# Дивний instanceof -In the code below, why does `instanceof` return `true`? We can easily see that `a` is not created by `B()`. +Чому `instanceof` повертає `true` у коді нижче? Ми можемо легко побачити, що `a` не створюється `B()`. ```js run function A() {} diff --git a/1-js/09-classes/06-instanceof/article.md b/1-js/09-classes/06-instanceof/article.md index f9db989ca..725d79251 100644 --- a/1-js/09-classes/06-instanceof/article.md +++ b/1-js/09-classes/06-instanceof/article.md @@ -1,42 +1,42 @@ -# Class checking: "instanceof" +# Перевірка класу: "instanceof" -The `instanceof` operator allows to check whether an object belongs to a certain class. It also takes inheritance into account. +Оператор `instanceof` дозволяє перевірити, чи належить об’єкт до певного класу. Він також враховує наслідування. -Such a check may be necessary in many cases. For example, it can be used for building a *polymorphic* function, the one that treats arguments differently depending on their type. +Така перевірка може знадобитися в багатьох випадках. Наприклад, його можна використати для створення *поліморфної* функції, яка обробляє аргументи по-різному залежно від їх типу. -## The instanceof operator [#ref-instanceof] +## Оператор instanceof [#ref-instanceof] -The syntax is: +Синтаксис такий: ```js obj instanceof Class ``` -It returns `true` if `obj` belongs to the `Class` or a class inheriting from it. +Він повертає `true`, якщо `obj` належить до класу `Class` або класу, який наслідується від нього. -For instance: +Наприклад: ```js run class Rabbit {} let rabbit = new Rabbit(); -// is it an object of Rabbit class? +// Чи це об’єкт класу Rabbit? *!* alert( rabbit instanceof Rabbit ); // true */!* ``` -It also works with constructor functions: +Він також працює з функціями-конструкторами: ```js run *!* -// instead of class +// замість класу function Rabbit() {} */!* alert( new Rabbit() instanceof Rabbit ); // true ``` -...And with built-in classes like `Array`: +...І з вбудованими класами як `Array`: ```js run let arr = [1, 2, 3]; @@ -44,19 +44,19 @@ alert( arr instanceof Array ); // true alert( arr instanceof Object ); // true ``` -Please note that `arr` also belongs to the `Object` class. That's because `Array` prototypically inherits from `Object`. +Будь ласка, зверніть увагу, що `arr` також належить до класу `Object`. Це тому, що клас `Array` прототипно наслідується від `Object`. -Normally, `instanceof` examines the prototype chain for the check. We can also set a custom logic in the static method `Symbol.hasInstance`. +Зазвичай, `instanceof` перевіряє ланцюжок прототипів. Ми також можемо задати будь-яку спеціальну логіку в статичному методі `Symbol.hasInstance`, і замінити звичайну поведінку. -The algorithm of `obj instanceof Class` works roughly as follows: +Алгоритм операції `obj instanceof Class` працює приблизно наступним чином: -1. If there's a static method `Symbol.hasInstance`, then just call it: `Class[Symbol.hasInstance](obj)`. It should return either `true` or `false`, and we're done. That's how we can customize the behavior of `instanceof`. +1. Якщо є статичний метод `Symbol.hasInstance`, тоді він просто викликаєтсья: `Class[Symbol.hasInstance](obj)`. Він повинен повернути `true` або `false`, ось і все. Ось як ми можемо задати поведінку `instanceof`. - For example: + Наприклад: ```js run - // setup instanceOf check that assumes that - // anything with canEat property is an animal + // задамо перевірку instanceof таким чином, + // що будь-що із властивістю canEat - це тварина class Animal { static [Symbol.hasInstance](obj) { if (obj.canEat) return true; @@ -65,24 +65,24 @@ The algorithm of `obj instanceof Class` works roughly as follows: let obj = { canEat: true }; - alert(obj instanceof Animal); // true: Animal[Symbol.hasInstance](obj) is called + alert(obj instanceof Animal); // true: Animal[Symbol.hasInstance](obj) було викликано ``` -2. Most classes do not have `Symbol.hasInstance`. In that case, the standard logic is used: `obj instanceOf Class` checks whether `Class.prototype` is equal to one of the prototypes in the `obj` prototype chain. +2. Більшість класів не мають `Symbol.hasInstance`. У цьому випадку використовується стандартна логіка: `obj instanceOf Class` перевіряє чи `Class.prototype` дорівнює одному з прототипів у ланцюжку прототипів `obj`. - In other words, compare one after another: + Іншими словами, прототипи порівнюються один за одним: ```js obj.__proto__ === Class.prototype? obj.__proto__.__proto__ === Class.prototype? obj.__proto__.__proto__.__proto__ === Class.prototype? ... - // if any answer is true, return true - // otherwise, if we reached the end of the chain, return false + // Якщо будь-яке з них буде true, то instanceof одразу ж верне true. + // Якщо ми досягли кінця ланцюжка - повертається false ``` - In the example above `rabbit.__proto__ === Rabbit.prototype`, so that gives the answer immediately. + У наведеному вище прикладі `rabbit.__proto__ === Rabbit.prototype`, тому ми знаходимо відповідь негайно. - In the case of an inheritance, the match will be at the second step: + У разі наслідування ми знайдемо те, що шукали, на другому кроці: ```js run class Animal {} @@ -93,76 +93,76 @@ The algorithm of `obj instanceof Class` works roughly as follows: alert(rabbit instanceof Animal); // true */!* - // rabbit.__proto__ === Animal.prototype (no match) + // rabbit.__proto__ === Animal.prototype (немає збігу) *!* - // rabbit.__proto__.__proto__ === Animal.prototype (match!) + // rabbit.__proto__.__proto__ === Animal.prototype (знайшли!) */!* ``` -Here's the illustration of what `rabbit instanceof Animal` compares with `Animal.prototype`: +Ось ілюстрація того, як операція `rabbit instanceof Animal` шукає `Animal.prototype` у прототипах: ![](instanceof.svg) -By the way, there's also a method [objA.isPrototypeOf(objB)](mdn:js/object/isPrototypeOf), that returns `true` if `objA` is somewhere in the chain of prototypes for `objB`. So the test of `obj instanceof Class` can be rephrased as `Class.prototype.isPrototypeOf(obj)`. +До речі, є також метод [objA.isPrototypeOf(objB)](mdn:js/object/isPrototypeOf), який повертає `true` якщо `objA` знаходиться десь у ланцюжку прототипів для `objB`. Отже, перевірку `obj instanceof Class` можна замінити на `Class.prototype.isPrototypeOf(obj)`. -It's funny, but the `Class` constructor itself does not participate in the check! Only the chain of prototypes and `Class.prototype` matters. +Цікаво, але сам класс `Class` не бере участі в перевірці! Має значення лише ланцюжок прототипів і `Class.prototype`. -That can lead to interesting consequences when a `prototype` property is changed after the object is created. +Це може призвести до дивних наслідків, коли властивість `prototype` було змінено після створення об’єкта. -Like here: +Як тут: ```js run function Rabbit() {} let rabbit = new Rabbit(); -// changed the prototype +// Змінюємо прототип Rabbit.prototype = {}; -// ...not a rabbit any more! +// ...це більше не rabbit! *!* alert( rabbit instanceof Rabbit ); // false */!* ``` -## Bonus: Object.prototype.toString for the type +## Бонус: Object.prototype.toString для визначення типу -We already know that plain objects are converted to string as `[object Object]`: +Ми вже знаємо, що прості об’єкти перетворюються на рядки як `[object Object]`: ```js run let obj = {}; alert(obj); // [object Object] -alert(obj.toString()); // the same +alert(obj.toString()); // теж саме ``` -That's their implementation of `toString`. But there's a hidden feature that makes `toString` actually much more powerful than that. We can use it as an extended `typeof` and an alternative for `instanceof`. +Це їх реалізація метода `toString`. Але є прихована функція, яка робить метод `toString` набагато потужнішим. Ми можемо використовувати його як розширений `typeof` і альтернативу `instanceof`. -Sounds strange? Indeed. Let's demystify. +Звучить дивно? Дійсно. Давайте розбиратися. -By [specification](https://tc39.github.io/ecma262/#sec-object.prototype.tostring), the built-in `toString` can be extracted from the object and executed in the context of any other value. And its result depends on that value. +У [специфікації](https://tc39.github.io/ecma262/#sec-object.prototype.tostring), вбудований метод `toString` можна витягнути з об’єкта та викликати в контексті будь-якого іншого значення. І результат залежить від типу цього значення. -- For a number, it will be `[object Number]` -- For a boolean, it will be `[object Boolean]` -- For `null`: `[object Null]` -- For `undefined`: `[object Undefined]` -- For arrays: `[object Array]` -- ...etc (customizable). +- Для числа це буде `[object Number]` +- Для логічного значення це буде `[object Boolean]` +- Для `null`: `[object Null]` +- Для `undefined`: `[object Undefined]` +- Для масивів: `[object Array]` +- ...тощо. -Let's demonstrate: +Давайте продемонструємо: ```js run -// copy toString method into a variable for convenience +// скопіюємо метод toString у змінну для зручності let objectToString = Object.prototype.toString; -// what type is this? +// Що це за тип? let arr = []; alert( objectToString.call(arr) ); // [object *!*Array*/!*] ``` -Here we used [call](mdn:js/function/call) as described in the chapter [](info:call-apply-decorators) to execute the function `objectToString` in the context `this=arr`. +Тут ми використали [call](mdn:js/function/call), як описано в розділі [](info:call-apply-decorators), щоб викликати функцію `objectToString` з контекстом `this=arr`. -Internally, the `toString` algorithm examines `this` and returns the corresponding result. More examples: +Всередені алгоритм `toString` перевіряє `this` і повертає відповідний результат. Більше прикладів: ```js run let s = Object.prototype.toString; @@ -174,9 +174,9 @@ alert( s.call(alert) ); // [object Function] ### Symbol.toStringTag -The behavior of Object `toString` can be customized using a special object property `Symbol.toStringTag`. +Поведінку методу об’єкта `toString` можна налаштувати за допомогою спеціальної властивості `Symbol.toStringTag`. -For instance: +Наприклад: ```js run let user = { @@ -186,10 +186,10 @@ let user = { alert( {}.toString.call(user) ); // [object User] ``` -For most environment-specific objects, there is such a property. Here are some browser specific examples: +Для більшості специфічних для середовища об’єктів така властивість є. Ось деякі приклади для браузера: ```js run -// toStringTag for the environment-specific object and class: +// toStringTag для специфічних для середовища об’єкту та класу: alert( window[Symbol.toStringTag]); // Window alert( XMLHttpRequest.prototype[Symbol.toStringTag] ); // XMLHttpRequest @@ -197,22 +197,22 @@ alert( {}.toString.call(window) ); // [object Window] alert( {}.toString.call(new XMLHttpRequest()) ); // [object XMLHttpRequest] ``` -As you can see, the result is exactly `Symbol.toStringTag` (if exists), wrapped into `[object ...]`. +Як бачите, результатом є саме `Symbol.toStringTag` (якщо існує), загорнутий у `[object ...]`. -At the end we have "typeof on steroids" that not only works for primitive data types, but also for built-in objects and even can be customized. +Наприкінці ми маємо "typeof на стероїдах", який працює не тільки для примітивних типів даних, але й для вбудованих об’єктів і навіть може бути кастомізований. -We can use `{}.toString.call` instead of `instanceof` for built-in objects when we want to get the type as a string rather than just to check. +Ми можемо використати `{}.toString.call` замість `instanceof` для вбудованих об’єктів, коли ми хочемо отримати тип у вигляді рядка, а не просто для перевірки. -## Summary +## Підсумки -Let's summarize the type-checking methods that we know: +Давайте підсумуємо відомі нам методи перевірки типів: -| | works for | returns | +| | працює для | повертає | |---------------|-------------|---------------| -| `typeof` | primitives | string | -| `{}.toString` | primitives, built-in objects, objects with `Symbol.toStringTag` | string | -| `instanceof` | objects | true/false | +| `typeof` | примітивів | рядок | +| `{}.toString` | примітивів, вбудованих об’єктів, об’єктів з `Symbol.toStringTag` | рядок | +| `instanceof` | об’єктів | true/false | -As we can see, `{}.toString` is technically a "more advanced" `typeof`. +Як ми бачимо, `{}.toString` технічно є "більш просунутим" `typeof`. -And `instanceof` operator really shines when we are working with a class hierarchy and want to check for the class taking into account inheritance. +І оператор `instanceof` дійсно сяє, коли ми працюємо з ієрархією класів і хочемо перевірити клас з урахуванням наслідування. From fba8269f46223e300ff47b85c2fe35b8b9390051 Mon Sep 17 00:00:00 2001 From: Stanislav Dolgachov Date: Mon, 10 Jan 2022 00:28:25 +0200 Subject: [PATCH 2/9] 1-js/10-error-handling/2-custom-errors: Translation --- .../2-custom-errors/1-format-error/task.md | 10 +- .../2-custom-errors/article.md | 130 +++++++++--------- 2 files changed, 70 insertions(+), 70 deletions(-) diff --git a/1-js/10-error-handling/2-custom-errors/1-format-error/task.md b/1-js/10-error-handling/2-custom-errors/1-format-error/task.md index 2c8e910fc..d5e200b61 100644 --- a/1-js/10-error-handling/2-custom-errors/1-format-error/task.md +++ b/1-js/10-error-handling/2-custom-errors/1-format-error/task.md @@ -2,13 +2,13 @@ importance: 5 --- -# Inherit from SyntaxError +# Успадкувати від SyntaxError -Create a class `FormatError` that inherits from the built-in `SyntaxError` class. +Створіть клас `FormatError`, який успадковується від вбудованого класу `SyntaxError`. -It should support `message`, `name` and `stack` properties. +Він повинен підтримувати властивості `message`, `name` та `stack`. -Usage example: +Приклад використання: ```js let err = new FormatError("formatting error"); @@ -18,5 +18,5 @@ alert( err.name ); // FormatError alert( err.stack ); // stack alert( err instanceof FormatError ); // true -alert( err instanceof SyntaxError ); // true (because inherits from SyntaxError) +alert( err instanceof SyntaxError ); // true (оскільки успадковується від SyntaxError) ``` diff --git a/1-js/10-error-handling/2-custom-errors/article.md b/1-js/10-error-handling/2-custom-errors/article.md index 918289319..8aa1f545b 100644 --- a/1-js/10-error-handling/2-custom-errors/article.md +++ b/1-js/10-error-handling/2-custom-errors/article.md @@ -1,42 +1,42 @@ -# Custom errors, extending Error +# Нестандартні помилки, розширення Error -When we develop something, we often need our own error classes to reflect specific things that may go wrong in our tasks. For errors in network operations we may need `HttpError`, for database operations `DbError`, for searching operations `NotFoundError` and so on. +Коли ми щось розробляємо, нам часто потрібні власні класи помилок, щоб відображати конкретні речі, які можуть піти не так у наших програмах. Для помилок у мережевих операціях нам може знадобитися `HttpError`, для операцій з базою даних `DbError`, для пошуку операцій `NotFoundError` тощо. -Our errors should support basic error properties like `message`, `name` and, preferably, `stack`. But they also may have other properties of their own, e.g. `HttpError` objects may have a `statusCode` property with a value like `404` or `403` or `500`. +Наші помилки повинні підтримувати основні властивості помилок, такі як `message`, `name` і, бажано, `stack`. Але вони також можуть мати інші властивості, наприклад, об’єкти `HttpError` можуть мати властивість `statusCode` зі значенням, як-от `404`, `403` або `500`. -JavaScript allows to use `throw` with any argument, so technically our custom error classes don't need to inherit from `Error`. But if we inherit, then it becomes possible to use `obj instanceof Error` to identify error objects. So it's better to inherit from it. +JavaScript дозволяє використовувати `throw` з будь-яким аргументом, тому технічно наші спеціальні класи помилок не повинні успадковуватись від `Error`. Але якщо ми успадкуємо, то стає можливим використовувати `obj instanceof Error` для ідентифікації об’єктів помилки. Тому краще успадкувати від нього. -As the application grows, our own errors naturally form a hierarchy. For instance, `HttpTimeoutError` may inherit from `HttpError`, and so on. +У міру розвитку програми наші власні помилки, природньо, утворюють ієрархію. Наприклад, `HttpTimeoutError` може успадковуватися від `HttpError` тощо. -## Extending Error +## Розширення Error -As an example, let's consider a function `readUser(json)` that should read JSON with user data. +Як приклад, давайте розглянемо функцію `readUser(json)`, яка повинна читати JSON з даними користувача. -Here's an example of how a valid `json` may look: +Ось приклад того, як може виглядати дійсний `json`: ```js -let json = `{ "name": "John", "age": 30 }`; +let json = `{ "name": "Іван", "age": 30 }`; ``` -Internally, we'll use `JSON.parse`. If it receives malformed `json`, then it throws `SyntaxError`. But even if `json` is syntactically correct, that doesn't mean that it's a valid user, right? It may miss the necessary data. For instance, it may not have `name` and `age` properties that are essential for our users. +Всередині ми будемо використовувати `JSON.parse`. Якщо він отримує неправильний `json`, він викидає `SyntaxError`. Але навіть якщо `json` синтаксично правильний, це не означає, що це дійсний користувач, чи не так? У ньому може не бути необхідних нам даних. Наприклад, він може не мати властивостей `name` та `age`, які є важливими для наших користувачів. -Our function `readUser(json)` will not only read JSON, but check ("validate") the data. If there are no required fields, or the format is wrong, then that's an error. And that's not a `SyntaxError`, because the data is syntactically correct, but another kind of error. We'll call it `ValidationError` and create a class for it. An error of that kind should also carry the information about the offending field. +Наша функція `readUser(json)` не тільки читатиме JSON, але й перевірятеме ("валідуватиме") дані. Якщо немає обов’язкових полів або формат неправильний, це помилка. І це не `SyntaxError`, оскільки дані синтаксично правильні, а інший тип помилки. Ми назвемо його `ValidationError` і створимо для нього окремий клас. Подібна помилка також повинна містити інформацію про поле, що порушує правила. -Our `ValidationError` class should inherit from the `Error` class. +Наш клас `ValidationError` має успадковуватись від класу `Error`. -The `Error` class is built-in, but here's its approximate code so we can understand what we're extending: +Клас `Error` є вбудованим, але ось його приблизний код, щоб ми могли зрозуміти, що ми розширюємо: ```js -// The "pseudocode" for the built-in Error class defined by JavaScript itself +// "Псевдокод" для вбудованого класу Error, визначеного самим JavaScript class Error { constructor(message) { this.message = message; - this.name = "Error"; // (different names for different built-in error classes) - this.stack = ; // non-standard, but most environments support it + this.name = "Error"; // (різні назви для різних вбудованих класів помилок) + this.stack = ; // нестандартна властивість, але більшість середовищ її підтримує } } ``` -Now let's inherit `ValidationError` from it and try it in action: +Тепер давайте успадкуємо від нього наш `ValidationError` і спробуємо його в дії: ```js run untrusted *!* @@ -49,23 +49,23 @@ class ValidationError extends Error { } function test() { - throw new ValidationError("Whoops!"); + throw new ValidationError("Упс!"); } try { test(); } catch(err) { - alert(err.message); // Whoops! + alert(err.message); // Упс! alert(err.name); // ValidationError - alert(err.stack); // a list of nested calls with line numbers for each + alert(err.stack); // список вкладених викликів з номерами рядків для кожного } ``` -Please note: in the line `(1)` we call the parent constructor. JavaScript requires us to call `super` in the child constructor, so that's obligatory. The parent constructor sets the `message` property. +Зверніть увагу: у рядку `(1)` ми викликаємо батьківський конструктор. JavaScript вимагає від нас викликати `super` у дочірньому конструкторі, це обов’язково. Батьківський конструктор встановлює властивість `message`. -The parent constructor also sets the `name` property to `"Error"`, so in the line `(2)` we reset it to the right value. +Батьківський конструктор також встановлює для властивості `name` значення `"Error"`, тому в рядку `(2)` ми скидаємо його до потрібного значення. -Let's try to use it in `readUser(json)`: +Давайте спробуємо використати його в `readUser(json)`: ```js run class ValidationError extends Error { @@ -89,7 +89,7 @@ function readUser(json) { return user; } -// Working example with try..catch +// Робочий приклад із try..catch try { let user = readUser('{ "age": 25 }'); @@ -101,31 +101,31 @@ try { } else if (err instanceof SyntaxError) { // (*) alert("JSON Syntax Error: " + err.message); } else { - throw err; // unknown error, rethrow it (**) + throw err; // невідома помилка, прокинемо її далі (**) } } ``` -The `try..catch` block in the code above handles both our `ValidationError` and the built-in `SyntaxError` from `JSON.parse`. +Блок `try..catch` у коді вище обробляє як нашу `ValidationError`, так і вбудовану `SyntaxError` з `JSON.parse`. -Please take a look at how we use `instanceof` to check for the specific error type in the line `(*)`. +Будь ласка, подивіться, як ми використовуємо `instanceof` для перевірки певного типу помилки в рядку `(*)`. -We could also look at `err.name`, like this: +Ми також можемо використати `err.name`, ось так: ```js // ... -// instead of (err instanceof SyntaxError) +// замість (err instanceof SyntaxError) } else if (err.name == "SyntaxError") { // (*) // ... ``` -The `instanceof` version is much better, because in the future we are going to extend `ValidationError`, make subtypes of it, like `PropertyRequiredError`. And `instanceof` check will continue to work for new inheriting classes. So that's future-proof. +Версія з `instanceof` набагато краща, тому що в майбутньому ми можемо розширити `ValidationError`, щоб створювати його підтипи, наприклад, `PropertyRequiredError`. І перевірка `instanceof` буде також працювати для нових спадкових класів. Так що це рішення залишиться надійним і далі. -Also it's important that if `catch` meets an unknown error, then it rethrows it in the line `(**)`. The `catch` block only knows how to handle validation and syntax errors, other kinds (caused by a typo in the code or other unknown reasons) should fall through. +Також важливо, що якщо `catch` зустрічає невідому помилку, він повторно викидає її в рядок `(**)`. Наш блок `catch` знає лише, як обробляти помилки перевірки правильності даних та синтаксису, інші типи (спричинені помилкою в коді або іншими невідомими причинами) потрібно прокинути далі. -## Further inheritance +## Подальше наслідування -The `ValidationError` class is very generic. Many things may go wrong. The property may be absent or it may be in a wrong format (like a string value for `age` instead of a number). Let's make a more concrete class `PropertyRequiredError`, exactly for absent properties. It will carry additional information about the property that's missing. +Клас `ValidationError` дуже загальний. Багато чого може піти не так. Властивість може бути відсутня або її значення має неправильний тип (наприклад, рядок у `age` замість числа). Давайте створимо більш конкретний клас `PropertyRequiredError`, саме для відсутніх властивостей. Він міститиме додаткову інформацію про властивість, якої немає. ```js run class ValidationError extends Error { @@ -159,7 +159,7 @@ function readUser(json) { return user; } -// Working example with try..catch +// Робочий приклад із try..catch try { let user = readUser('{ "age": 25 }'); @@ -173,18 +173,18 @@ try { } else if (err instanceof SyntaxError) { alert("JSON Syntax Error: " + err.message); } else { - throw err; // unknown error, rethrow it + throw err; // невідома помилка, прокинути далі } } ``` -The new class `PropertyRequiredError` is easy to use: we only need to pass the property name: `new PropertyRequiredError(property)`. The human-readable `message` is generated by the constructor. +Новий клас `PropertyRequiredError` простий у використанні: нам потрібно лише передати ім’я властивості: `new PropertyRequiredError(property)`. Повідомлення `message` у зрозумілому вигляді генерується його конструктором. -Please note that `this.name` in `PropertyRequiredError` constructor is again assigned manually. That may become a bit tedious -- to assign `this.name = ` in every custom error class. We can avoid it by making our own "basic error" class that assigns `this.name = this.constructor.name`. And then inherit all our custom errors from it. +Зверніть увагу, що `this.name` у конструкторі `PropertyRequiredError` знову призначається вручну. Це може набриднути -- призначати `this.name = <ім’я класу>` у кожному спеціальному класі помилок. Ми можемо уникнути цього, створивши наш власний клас "базова помилка", який призначає `this.name = this.constructor.name`. А потім успадковувати всі наші власні помилки від нього. -Let's call it `MyError`. +Назвемо його `MyError`. -Here's the code with `MyError` and other custom error classes, simplified: +Ось спрощений код із `MyError` та іншими класами помилок: ```js run class MyError extends Error { @@ -205,51 +205,51 @@ class PropertyRequiredError extends ValidationError { } } -// name is correct +// правильна name alert( new PropertyRequiredError("field").name ); // PropertyRequiredError ``` -Now custom errors are much shorter, especially `ValidationError`, as we got rid of the `"this.name = ..."` line in the constructor. +Тепер наші помилки набагато коротші, особливо `ValidationError`, оскільки ми позбулися рядка `"this.name = ..."` у конструкторі. -## Wrapping exceptions +## Обгортання винятків -The purpose of the function `readUser` in the code above is "to read the user data". There may occur different kinds of errors in the process. Right now we have `SyntaxError` and `ValidationError`, but in the future `readUser` function may grow and probably generate other kinds of errors. +Метою функції `readUser` у коді вище є "читати дані користувача". У процесі можуть виникати різного роду помилки. Зараз ми маємо `SyntaxError` і `ValidationError`, але в майбутньому функції `readUser` може бути розширино і, ймовірно, вона генеруватиме інші види помилок. -The code which calls `readUser` should handle these errors. Right now it uses multiple `if`s in the `catch` block, that check the class and handle known errors and rethrow the unknown ones. +Тому код, який викликає `readUser`, повинен обробляти ці помилки. Зараз він використовує кілька `if` у блоці `catch`, які перевіряють клас, обробляють відомі помилки та прокидують далі невідомі. -The scheme is like this: +Схема така: ```js try { ... - readUser() // the potential error source + readUser() // потенційне джерело помилки ... } catch (err) { if (err instanceof ValidationError) { - // handle validation errors + // обробити помилки перевірки даних } else if (err instanceof SyntaxError) { - // handle syntax errors + // обробити синтаксичні помилки } else { - throw err; // unknown error, rethrow it + throw err; // невідома помилка, прокинути далі } } ``` -In the code above we can see two types of errors, but there can be more. +У коді вище ми бачимо два типи помилок, але їх може бути більше. -If the `readUser` function generates several kinds of errors, then we should ask ourselves: do we really want to check for all error types one-by-one every time? +Якщо функція `readUser` генерує кілька типів помилок, тоді ми повинні запитати себе: чи дійсно ми хочемо щоразу перевіряти всі типи помилок одну за одною? -Often the answer is "No": we'd like to be "one level above all that". We just want to know if there was a "data reading error" -- why exactly it happened is often irrelevant (the error message describes it). Or, even better, we'd like to have a way to get the error details, but only if we need to. +Часто відповідь "ні": ми б хотіли бути "на один рівень вище всього цього". Ми просто хочемо знати, чи сталася "помилка читання даних" -- чому саме це сталося, часто не має значення (це описує повідомлення про помилку). Або, ще краще, ми хотіли б мати спосіб отримати деталі помилки, але лише за необхідності. -The technique that we describe here is called "wrapping exceptions". +Техніка, яку ми тут описуємо, називається "обгортання винятків". -1. We'll make a new class `ReadError` to represent a generic "data reading" error. -2. The function `readUser` will catch data reading errors that occur inside it, such as `ValidationError` and `SyntaxError`, and generate a `ReadError` instead. -3. The `ReadError` object will keep the reference to the original error in its `cause` property. +1. Ми створимо новий клас `ReadError`, щоб представляти загальну помилку "читання даних". +2. Функція `readUser` буде ловити помилки читання даних, які виникають всередині неї, наприклад, `ValidationError` і `SyntaxError`, і натомість генеруватиме `ReadError`. +3. Об’єкт `ReadError` зберігатиме посилання на вихідну помилку у своїй властивості `cause`. -Then the code that calls `readUser` will only have to check for `ReadError`, not for every kind of data reading errors. And if it needs more details of an error, it can check its `cause` property. +Тоді код, який викликає `readUser`, повинен буде перевіряти лише `ReadError`, а не всі види помилок читання даних. І якщо йому потрібні додаткові відомості про помилку, він може перевірити її властивість `cause`. -Here's the code that defines `ReadError` and demonstrates its use in `readUser` and `try..catch`: +Ось код, який визначає `ReadError` та демонструє його використання в `readUser` та `try..catch`: ```js run class ReadError extends Error { @@ -317,14 +317,14 @@ try { } ``` -In the code above, `readUser` works exactly as described -- catches syntax and validation errors and throws `ReadError` errors instead (unknown errors are rethrown as usual). +У наведеному вище коді `readUser` працює, як описано -- ловить синтаксичні помилки та помилки перевірки даних та замість цього кидає помилки `ReadError` (невідомі помилки прокидуються далі, як і раніше). -So the outer code checks `instanceof ReadError` and that's it. No need to list all possible error types. +Отже, зовнішній код перевіряє `instanceof ReadError` і все. Немає необхідності перевіряти всі можливі типи помилок. -The approach is called "wrapping exceptions", because we take "low level" exceptions and "wrap" them into `ReadError` that is more abstract. It is widely used in object-oriented programming. +Цей підхід називається "обгортання винятків", тому що ми беремо винятки "низького рівня" і "загортаємо" їх у `ReadError`, що є більш абстрактним. Такий підхід широко використовується в об’єктно-орієнтованому програмуванні. -## Summary +## Підсумки -- We can inherit from `Error` and other built-in error classes normally. We just need to take care of the `name` property and don't forget to call `super`. -- We can use `instanceof` to check for particular errors. It also works with inheritance. But sometimes we have an error object coming from a 3rd-party library and there's no easy way to get its class. Then `name` property can be used for such checks. -- Wrapping exceptions is a widespread technique: a function handles low-level exceptions and creates higher-level errors instead of various low-level ones. Low-level exceptions sometimes become properties of that object like `err.cause` in the examples above, but that's not strictly required. +- Зазвичай класи своїх помилок ми можемо успадковувати від `Error` та інших вбудованих класів. Нам просто потрібно подбати про властивість `name` і не забути викликати `super`. +- Ми можемо використовувати `instanceof` для перевірки певних помилок. Це також працює зі спадковістю. Але іноді ми маємо об’єкт помилки, який надходить із бібліотеки від сторонніх розробників, і немає простого способу отримати його клас. Тоді для таких перевірок можна використовувати властивість `name`. +- Обгортання винятків є широко поширеною технікою: функція обробляє винятки низького рівня і створює помилки вищого рівня замість різноманітних низькорівневих. Винятки низького рівня іноді стають властивостями цього об’єкта, наприклад, `err.cause`, як у наведених вище прикладах, але це не є суворо обов’язковим. From f20ee14f397e15a2244a2532afb5d9acc92498b7 Mon Sep 17 00:00:00 2001 From: Stanislav Dolgachov Date: Thu, 20 Jan 2022 16:36:49 +0200 Subject: [PATCH 3/9] Translate 2-ui titles --- 2-ui/1-document/index.md | 4 ++-- 2-ui/2-events/index.md | 4 ++-- 2-ui/3-event-details/index.md | 4 ++-- 2-ui/4-forms-controls/index.md | 4 ++-- 2-ui/5-loading/index.md | 2 +- 2-ui/99-ui-misc/index.md | 2 +- 2-ui/index.md | 4 ++-- 7 files changed, 12 insertions(+), 12 deletions(-) diff --git a/2-ui/1-document/index.md b/2-ui/1-document/index.md index 1b60cdf2c..5377e865c 100644 --- a/2-ui/1-document/index.md +++ b/2-ui/1-document/index.md @@ -1,3 +1,3 @@ -# Document +# Документ -Here we'll learn to manipulate a web-page using JavaScript. +Тут ми навчимося маніпулювати веб-сторінкою за допомогою JavaScript. diff --git a/2-ui/2-events/index.md b/2-ui/2-events/index.md index f4996083c..eb0c6a7dc 100644 --- a/2-ui/2-events/index.md +++ b/2-ui/2-events/index.md @@ -1,3 +1,3 @@ -# Introduction to Events +# Вступ до подій -An introduction to browser events, event properties and handling patterns. +Вступ до браузерних подій, їх властивостей і шаблонів обробки. diff --git a/2-ui/3-event-details/index.md b/2-ui/3-event-details/index.md index 569f08137..9371c2b3a 100644 --- a/2-ui/3-event-details/index.md +++ b/2-ui/3-event-details/index.md @@ -1,3 +1,3 @@ -# UI Events +# Інтерфейсні події -Here we cover most important user interface events and how to work with them. +Тут ми розповідаємо про найважливіші події інтерфейсу та як з ними працювати. diff --git a/2-ui/4-forms-controls/index.md b/2-ui/4-forms-controls/index.md index 726474b19..592c6d308 100644 --- a/2-ui/4-forms-controls/index.md +++ b/2-ui/4-forms-controls/index.md @@ -1,3 +1,3 @@ -# Forms, controls +# Форми та інтерактивні елементи -Special properties and events for forms `
` and controls: ``, ``, `