diff --git a/1-js/09-classes/01-class/1-rewrite-to-class/task.md b/1-js/09-classes/01-class/1-rewrite-to-class/task.md index 4477de679..982872108 100644 --- a/1-js/09-classes/01-class/1-rewrite-to-class/task.md +++ b/1-js/09-classes/01-class/1-rewrite-to-class/task.md @@ -2,8 +2,8 @@ importance: 5 --- -# Rewrite to class +# Перепишіть клас -The `Clock` class (see the sandbox) is written in functional style. Rewrite it in the "class" syntax. +Клас `Clock` написано в функціональному стилі. Перепишіть його в синтаксис класу. -P.S. The clock ticks in the console, open it to see. +P.S. Годинник тікає у консолі, відкрийте її, щоб побачити. diff --git a/1-js/09-classes/01-class/article.md b/1-js/09-classes/01-class/article.md index d19b9ca9a..93474b143 100644 --- a/1-js/09-classes/01-class/article.md +++ b/1-js/09-classes/01-class/article.md @@ -1,22 +1,22 @@ -# Class basic syntax +# Базовий синтаксис класу -```quote author="Wikipedia" -In object-oriented programming, a *class* is an extensible program-code-template for creating objects, providing initial values for state (member variables) and implementations of behavior (member functions or methods). +```quote author="Вікіпедія" +В об’єктно-орієнтованому програмуванні, *клас* -- це спеціальна конструкція, яка використовується для групування пов’язаних змінних та функцій. При цьому, згідно з термінологією ООП, глобальні змінні класу (члени-змінні) називаються полями даних (також властивостями або атрибутами), а члени-функції називають методами класу. ``` -In practice, we often need to create many objects of the same kind, like users, or goods or whatever. +На практиці ми часто повинні створювати багато об’єктів одного й того ж виду, наприклад користувачів, або товари чи що завгодно. -As we already know from the chapter , `new function` can help with that. +Як ми вже знаємо з розділу , `new function` може допомогти з цим. -But in the modern JavaScript, there's a more advanced "class" construct, that introduces great new features which are useful for object-oriented programming. +Але в сучасному JavaScript існує більш просунута конструкція "клас", яка вводить нові чудові функції, які корисні для об’єктно-орієнтованого програмування. -## The "class" syntax +## Синтаксис "class" -The basic syntax is: +Основний синтаксис: ```js class MyClass { - // class methods + // методи класу constructor() { ... } method1() { ... } method2() { ... } @@ -25,11 +25,11 @@ class MyClass { } ``` -Then use `new MyClass()` to create a new object with all the listed methods. +Потім використовуйте `new MyClass()`, щоб створити новий об’єкт з усіма перерахованими методами. -The `constructor()` method is called automatically by `new`, so we can initialize the object there. +Метод `constructor()` викликається автоматично за допомогою `new`, в ньому ми можемо ініціалізувати об’єкт. -For example: +Наприклад: ```js run class User { @@ -44,33 +44,33 @@ class User { } -// Usage: -let user = new User("John"); +// Використання: +let user = new User("Іван"); user.sayHi(); ``` -When `new User("John")` is called: -1. A new object is created. -2. The `constructor` runs with the given argument and assigns it to `this.name`. +Коли `new User("John")` викликається: +1. Створюється новий об’єкт. +2. `constructor` запускається з даними аргументом і присвоює його `this.name`. -...Then we can call object methods, such as `user.sayHi()`. +...Потім ми можемо викликати методи об’єкту, такі як `user.sayHi()`. -```warn header="No comma between class methods" -A common pitfall for novice developers is to put a comma between class methods, which would result in a syntax error. +```warn header="Кома між методами класу не потрібна" +Часта помилка для розробників-початківців полягає в тому, щоб поставити кому між методами класу, що призведе до помилки синтаксису. -The notation here is not to be confused with object literals. Within the class, no commas are required. +Позначення тут не слід плутати з літералами об’єктів. У межах класу не треба ставити кому. ``` -## What is a class? +## Що таке клас? -So, what exactly is a `class`? That's not an entirely new language-level entity, as one might think. +Отже, що саме -- `class`? Він не є цілком новим ступенем мови програмування, як можна подумати. -Let's unveil any magic and see what a class really is. That'll help in understanding many complex aspects. +Розкриймо будь-яку магію і подивимося, що дійсно таке клас. Це допоможе в розумінні багатьох складних аспектів. -In JavaScript, a class is a kind of function. +У JavaScript клас є своєрідною функцією. -Here, take a look: +Погляньте на це: ```js run class User { @@ -78,24 +78,24 @@ class User { sayHi() { alert(this.name); } } -// proof: User is a function +// доказ: User -- це функція *!* alert(typeof User); // function */!* ``` -What `class User {...}` construct really does is: +Що конструкція `class User {...}` дійсно робить: -1. Creates a function named `User`, that becomes the result of the class declaration. The function code is taken from the `constructor` method (assumed empty if we don't write such method). -2. Stores class methods, such as `sayHi`, in `User.prototype`. +1. Створює функцію, що називається `User` та стає результатом оголошення класу. Код функції береться з методу `constructor` (приймається порожнім, якщо ми не написали такий метод). +2. Зберігає методи класу, такі як `sayHi`, `User.prototype`. -After `new User` object is created, when we call its method, it's taken from the prototype, just as described in the chapter . So the object has access to class methods. +Після того, як `new User` створився, коли ми викликаємо його метод, він береться з прототипу, як описано в розділі . Таким чином, об’єкт має доступ до методів класу. -We can illustrate the result of `class User` declaration as: +Ми можемо проілюструвати результат оголошення `class User` наступним чином: ![](class-user.svg) -Here's the code to introspect it: +Ось код, щоб проаналізувати це: ```js run class User { @@ -103,50 +103,50 @@ class User { sayHi() { alert(this.name); } } -// class is a function +// клас -- це функція alert(typeof User); // function -// ...or, more precisely, the constructor method +// ...або, точніше, метод конструктора alert(User === User.prototype.constructor); // true -// The methods are in User.prototype, e.g: -alert(User.prototype.sayHi); // the code of the sayHi method +// Методи знаходяться в User.prototype, наприклад: +alert(User.prototype.sayHi); // код sayHi методу -// there are exactly two methods in the prototype +// у прототипі існує рівно два методи alert(Object.getOwnPropertyNames(User.prototype)); // constructor, sayHi ``` -## Not just a syntactic sugar +## Не просто синтаксичний цукор -Sometimes people say that `class` is a "syntactic sugar" (syntax that is designed to make things easier to read, but doesn't introduce anything new), because we could actually declare the same without `class` keyword at all: +Іноді люди кажуть, що `class` -- це "синтаксичний цукор" (синтаксис, який призначений для того, щоб зробити речі легше для читання, але не вводить нічого нового), тому що ми могли б фактично оголосити те ж саме взагалі без ключового слова `class`: ```js run -// rewriting class User in pure functions +// переписування класу User в чистих функціях -// 1. Create constructor function +// 1. Створити функцію-конструктор function User(name) { this.name = name; } -// a function prototype has "constructor" property by default, -// so we don't need to create it +// прототип функції має властивість "constructor" за замовчуванням, +// тому нам не потрібно її створювати -// 2. Add the method to prototype +// 2. Додати метод до прототипу User.prototype.sayHi = function() { alert(this.name); }; -// Usage: -let user = new User("John"); +// Використання: +let user = new User("Іван"); user.sayHi(); ``` -The result of this definition is about the same. So, there are indeed reasons why `class` can be considered a syntactic sugar to define a constructor together with its prototype methods. +Результат цього оголошення дуже схожий. Отже, дійсно існують причини, чому `class` можна вважати синтаксичним цукром для того, щоб визначити конструктор разом із методами прототипу. -Still, there are important differences. +Проте, існують важливі відмінності. -1. First, a function created by `class` is labelled by a special internal property `[[IsClassConstructor]]: true`. So it's not entirely the same as creating it manually. +1. По-перше, функція, що створена за допомогою `class`, позначена спеціальною внутрішньою власністю `[[IsClassConstructor]]: true`. Так що це не зовсім те ж саме, що і створити її вручну. - The language checks for that property in a variety of places. For example, unlike a regular function, it must be called with `new`: + Мовна перевіряє цю властивість у різних місцях. Наприклад, на відміну від звичайної функції, її треба викликати з `new`: ```js run class User { @@ -157,7 +157,7 @@ Still, there are important differences. User(); // Error: Class constructor User cannot be invoked without 'new' ``` - Also, a string representation of a class constructor in most JavaScript engines starts with the "class..." + Також, представлення конструктора класу у вигляді рядка у більшості рушіїв JavaScript починається з "class..." ```js run class User { @@ -166,55 +166,55 @@ Still, there are important differences. alert(User); // class User { ... } ``` - There are other differences, we'll see them soon. + Є також інші відмінності, ми побачимо їх найближчим часом. -2. Class methods are non-enumerable. - A class definition sets `enumerable` flag to `false` for all methods in the `"prototype"`. +2. Методи класу неперелічувані. + Оголошення класу встановлює `enumerable` прапор у `false` для всіх методів в `"prototype"`. - That's good, because if we `for..in` over an object, we usually don't want its class methods. + Це добре тому, що коли ми проходимо через об’єкт за допомогою `for..in`, ми зазвичай не хочемо мати справу з методами класу. -3. Classes always `use strict`. - All code inside the class construct is automatically in strict mode. +3. Клас завжди `use strict`. + Весь код всередині конструкції класу автоматично знаходиться в строгому режимі. -Besides, `class` syntax brings many other features that we'll explore later. +Крім того, синтаксис `class` приносить багато інших особливостей, які ми дослідимо пізніше. ## Class Expression -Just like functions, classes can be defined inside another expression, passed around, returned, assigned, etc. +Так само, як функції, класи можуть бути визначені всередині іншого виразу, передані, повернуті, присвоєні та ін. -Here's an example of a class expression: +Ось приклад class expression: ```js let User = class { sayHi() { - alert("Hello"); + alert("Привіт"); } }; ``` -Similar to Named Function Expressions, class expressions may have a name. +Подібно до Named Function Expression, class expression може мати назву. -If a class expression has a name, it's visible inside the class only: +Якщо class expression має назву, то її видно лише у класі: ```js run // "Named Class Expression" -// (no such term in the spec, but that's similar to Named Function Expression) +// (немає такого терміну у специфікації, але це схоже на Named Function Expression) let User = class *!*MyClass*/!* { sayHi() { - alert(MyClass); // MyClass name is visible only inside the class + alert(MyClass); // назву MyClass видно тільки всередині класу } }; -new User().sayHi(); // works, shows MyClass definition +new User().sayHi(); // працює, показує визначення MyClass -alert(MyClass); // error, MyClass name isn't visible outside of the class +alert(MyClass); // помилка, назву MyClass не видно за межами класу ``` -We can even make classes dynamically "on-demand", like this: +Ми можемо навіть зробити класи динамічними "на вимогу", наприклад: ```js run function makeClass(phrase) { - // declare a class and return it + // оголошуємо клас і повертаємо його return class { sayHi() { alert(phrase); @@ -222,24 +222,24 @@ function makeClass(phrase) { }; } -// Create a new class -let User = makeClass("Hello"); +// Створюємо новий клас +let User = makeClass("Привіт"); -new User().sayHi(); // Hello +new User().sayHi(); // Привіт ``` -## Getters/setters +## Геттери/сеттери -Just like literal objects, classes may include getters/setters, computed properties etc. +Подібно до літералів об’єктів, класи можуть включати геттери/сеттери, обчислені назви властивостей тощо. -Here's an example for `user.name` implemented using `get/set`: +Ось приклад для `user.name`, що реалізований за допомогою `get/set`: ```js run class User { constructor(name) { - // invokes the setter + // викликає сеттер this.name = name; } @@ -253,7 +253,7 @@ class User { set name(value) { */!* if (value.length < 4) { - alert("Name is too short."); + alert("Ім’я занадто коротке."); return; } this._name = value; @@ -261,17 +261,17 @@ class User { } -let user = new User("John"); -alert(user.name); // John +let user = new User("Іван"); +alert(user.name); // Іван -user = new User(""); // Name is too short. +user = new User(""); // Ім’я занадто коротке. ``` -Technically, such class declaration works by creating getters and setters in `User.prototype`. +Технічно, таке оголошення класу працює шляхом створення геттерів та сеттерів в `User.prototype`. -## Computed names [...] +## Обчислені назви [...] -Here's an example with a computed method name using brackets `[...]`: +Ось приклад з обчисленою назвою методу за допомогою використання дужок `[...]`: ```js run class User { @@ -279,7 +279,7 @@ class User { *!* ['say' + 'Hi']() { */!* - alert("Hello"); + alert("Привіт"); } } @@ -287,71 +287,71 @@ class User { new User().sayHi(); ``` -Such features are easy to remember, as they resemble that of literal objects. +Такі особливості легко запам’ятати, оскільки вони нагадують літерали об’єктів. -## Class fields +## Поля класу -```warn header="Old browsers may need a polyfill" -Class fields are a recent addition to the language. +```warn header="Старим браузерам може знадобитися поліфіл" +Поля класу -- це недавнє доповнення до мови. ``` -Previously, our classes only had methods. +Раніше наші класи мали лише методи. -"Class fields" is a syntax that allows to add any properties. +"Поля класу" -- це синтаксис, який дозволяє додавати будь-які властивості. -For instance, let's add `name` property to `class User`: +Наприклад, додаймо властивість `name` до `class User`: ```js run class User { *!* - name = "John"; + name = "Іван"; */!* sayHi() { - alert(`Hello, ${this.name}!`); + alert(`Привіт, ${this.name}!`); } } -new User().sayHi(); // Hello, John! +new User().sayHi(); // Привіт, Іван! ``` -So, we just write " = " in the declaration, and that's it. +Отже, ми просто пишемо " = " в оголошенні, і це все. -The important difference of class fields is that they are set on individual objects, not `User.prototype`: +Важливою відмінністю полів класу є те, що вони встановлюються на окремих об’єктах, а не в `User.prototype`: ```js run class User { *!* - name = "John"; + name = "Іван"; */!* } let user = new User(); -alert(user.name); // John +alert(user.name); // Іван alert(User.prototype.name); // undefined ``` -We can also assign values using more complex expressions and function calls: +Ми також можемо присвоїти значення, використовуючи складніші вирази та виклики функції: ```js run class User { *!* - name = prompt("Name, please?", "John"); + name = prompt("Ім’я, будь ласка?", "Іван"); */!* } let user = new User(); -alert(user.name); // John +alert(user.name); // Іван ``` -### Making bound methods with class fields +### Створення методів, що пов’язані з полями класу -As demonstrated in the chapter functions in JavaScript have a dynamic `this`. It depends on the context of the call. +Як показано в розділі , функції в JavaScript мають динамічний `this`. Він залежить від контексту виклику. -So if an object method is passed around and called in another context, `this` won't be a reference to its object any more. +Отже, якщо метод об’єкта передається і викликається в іншому контексті, `this` більше не буде посиланням на цей об’єкт. -For instance, this code will show `undefined`: +Наприклад, цей код покаже `undefined`: ```js run class Button { @@ -364,21 +364,21 @@ class Button { } } -let button = new Button("hello"); +let button = new Button("привіт"); *!* setTimeout(button.click, 1000); // undefined */!* ``` -The problem is called "losing `this`". +Ця проблема називається "втратою `this`". -There are two approaches to fixing it, as discussed in the chapter : +Існує два підходи до розв'язання цієї проблеми, як обговорювалося в розділі : -1. Pass a wrapper-function, such as `setTimeout(() => button.click(), 1000)`. -2. Bind the method to object, e.g. in the constructor. +1. Передати функцію-обгортку, наприклад `setTimeout(() => button.click(), 1000)`. +2. Зв’язати метод з об’єктом за допомогою функції `bind`, наприклад у конструкторі. -Class fields provide another, quite elegant syntax: +Поля класу надають інший, досить елегантний синтаксис: ```js run class Button { @@ -392,37 +392,37 @@ class Button { */!* } -let button = new Button("hello"); +let button = new Button("привіт"); -setTimeout(button.click, 1000); // hello +setTimeout(button.click, 1000); // привіт ``` -The class field `click = () => {...}` is created on a per-object basis, there's a separate function for each `Button` object, with `this` inside it referencing that object. We can pass `button.click` around anywhere, and the value of `this` will always be correct. +Поле класу `click = () => {...}` створюється на основі конкретного об’єкта, існує окрема функція для кожного об’єкта `Button`, з `this` всередині неї, що посилається на цей об’єкт. Ми можемо передати кнопку куди завгодно, а значення `this` завжди буде коректним. -That's especially useful in browser environment, for event listeners. +Це особливо корисно в середовищі браузера, для слухачів подій. -## Summary +## Підсумки -The basic class syntax looks like this: +Основний синтаксис класу виглядає так: ```js class MyClass { - prop = value; // property + prop = value; // властивість - constructor(...) { // constructor + constructor(...) { // конструктор // ... } - method(...) {} // method + method(...) {} // метод - get something(...) {} // getter method - set something(...) {} // setter method + get something(...) {} // геттер метод + set something(...) {} // сеттер метод - [Symbol.iterator]() {} // method with computed name (symbol here) + [Symbol.iterator]() {} // метод з обчисленим ім’ям (символом в цьому випадку) // ... } ``` -`MyClass` is technically a function (the one that we provide as `constructor`), while methods, getters and setters are written to `MyClass.prototype`. +`MyClass` технічно є функцією (тою, яку ми надаємо як `constructor`), тоді як методи, геттери та сеттери записуються до `MyClass.prototype`. -In the next chapters we'll learn more about classes, including inheritance and other features. +У наступних розділах ми дізнаємося більше про класи, включаючи наслідування та інші особливості.