Наповнення JS розділу

Добридень, Пані та Панове, завдяки вам вдалося зібрати більше 19тис грн з необхідних 15тис на впровадження JS розділу.

JS розділ вже впроваджено - переходимо до його наповнення і почнемо бігти довгий марафон, адже JS має більше 1100 різноманітних методів, властивостей, подій і т.д., які необхідно описати.

Будемо працювати, і вдень, і вночі, щоб орієнтовно взимку закінчити наповнювати JS розділ!

Ви також можете допомогти нам в цьому. Долучайтеся до нашої спільноти в дискорді - ставайте її частиною і допомагайте нашому розвитку.

Також, підтримуйте нас матеріально.

JS об'єкт Class

Визначення класів

Класи в дійсності є "спеціальними функціями". Так само, як ви може визначити вирази та декларації функцій, можна визначити класи двома шляхами: використовуючи вираз класу або його декларацію.

// Декларація
class Rectangle {
  constructor(height, width) {
    this.height = height;
    this.width = width;
  }
}

// Вираз; клас є анонімним, але призначений змінній
const Rectangle = class {
  constructor(height, width) {
    this.height = height;
    this.width = width;
  }
};

// Вираз; клас має своє власне ім'я
const Rectangle = class Rectangle2 {
  constructor(height, width) {
    this.height = height;
    this.width = width;
  }
};

Такі вирази класів можуть бути як анонімними, так і мати власне ім'я, відмінне від імені змінної, до якої вони присвоєні. Проте, на відміну від декларацій функцій, декларації класів мають ті ж самі обмеження "мертвої зони", як і ключові слова let та const, і ведуть себе так, ніби не відбувається їхнє переміщення на початок області видимості

Тіло класу

Тіло класу розташоване у фігурних дужках {}. Саме тут ви визначаєте члени класу, такі як методи чи конструктор.

Тіло класу виконується в строгому режимі навіть без директиви "use strict".

Елемент класу може бути охарактеризований трьома аспектами:

Тип: Геттер (getter), сеттер (setter), метод або поле. Розташування: Статичне чи екземпляра. Видимість: Публічний чи приватний.

Разом вони утворюють 16 можливих комбінацій.

Конструктор

Конструктор - це спеціальний метод для створення та ініціалізації об'єкта, створеного класом. В класі може бути лише один спеціальний метод із ім'ям "конструктор" — якщо клас містить більше одного входження методу конструктора, буде викинута помилка SyntaxError.

Конструктор може використовувати ключове слово super для виклику конструктора батьківського класу.

Ви можете створювати властивості екземпляра всередині конструктора:

class Rectangle {
  constructor(height, width) {
    this.height = height;
    this.width = width;
  }
}

Блоки статичної ініціалізації

Блоки статичної ініціалізації відкривають широкі можливості для налаштування статичних властивостей. Вони дозволяють проводити оцінювання виразів на етапі ініціалізації і надають доступ до приватної області видимості.

Можливе оголошення декількох статичних блоків, які можна комбінувати з декларуванням статичних полів і методів. При цьому всі статичні елементи будуть оцінюватися в послідовності їх оголошення.

Методи

Кожен метод визначається в прототипі відповідного екземпляра класу і є спільним для всіх його екземплярів. Ці методи можуть бути представлені у вигляді звичайних функцій, асинхронних функцій, функцій-генераторів або асинхронних функцій-генераторів.

class Rectangle {
  constructor(height, width) {
    this.height = height;
    this.width = width;
  }
  // Getter
  get area() {
    return this.calcArea();
  }
  // Method
  calcArea() {
    return this.height * this.width;
  }
  *getSides() {
    yield this.height;
    yield this.width;
    yield this.height;
    yield this.width;
  }
}

const square = new Rectangle(10, 10);

console.log(square.area); // 100
console.log([...square.getSides()]); // [10, 10, 10, 10]

Статичні методи та поля у класах

Ключове слово static слугує для визначення статичних методів або полів класу. На відміну від звичайних властивостей, які відносяться до конкретного екземпляра, статичні властивості встановлюються на рівні самого класу. Статичні методи зазвичай використовуються як універсальні функції для додатків, а статичні поля можна застосовувати для кешування, фіксованих конфігурацій або для даних, які не вимагають копіювання між різними екземплярами.

class Point {
  constructor(x, y) {
    this.x = x;
    this.y = y;
  }

  static displayName = "Point";
  static distance(a, b) {
    const dx = a.x - b.x;
    const dy = a.y - b.y;

    return Math.hypot(dx, dy);
  }
}

const p1 = new Point(5, 5);
const p2 = new Point(10, 10);
p1.displayName; // undefined
p1.distance; // undefined
p2.displayName; // undefined
p2.distance; // undefined

console.log(Point.displayName); // "Point"
console.log(Point.distance(p1, p2)); // 7.0710678118654755

Оголошення полів в класах

Використовуючи синтаксис оголошення полів класу, наступний конструктор можна виразити так:

class Rectangle {
  height = 0;
  width;
  constructor(height, width) {
    this.height = height;
    this.width = width;
  }
}

Поля класу схожі на властивості об'єктів, а не змінні, тому для їх оголошення ми не вживаємо ключові слова типу const. У JavaScript для приватних елементів використовується специфічний синтаксис, тому слова, такі як public чи private, також не вживаються.

Як показано вище, поля можуть бути оголошені зі значенням за замовчуванням або без нього. Поля без цього значення автоматично приймають undefined. Завдяки передбачуваному оголошенню полів, визначення класів стає більш прозорим, а постійна наявність полів сприяє оптимізації коду.

Приватні елементи класу

Використовуючи приватні поля, можна докладніше визначити клас наступним чином:

class Rectangle {
  #height = 0;
  #width;
  constructor(height, width) {
    this.#height = height;
    this.#width = width;
  }
}

Спроба звернутися до приватних полів поза межами класу призведе до помилки; ці поля доступні лише всередині класу. Встановлюючи елементи недоступними зовні, ви запобігаєте небажаній залежності від внутрішнього устрою класу, який може змінюватись.

Оголошення приватних полів можливе лише на стадії їх визначення. Неможливо створити їх пізніше через присвоєння, на відміну від звичних властивостей класу.

Спадкування в класах

Для створення класу як дочірнього елементу іншого конструктора (класу або функції) використовується ключове слово extends.

class Animal {
  constructor(name) {
    this.name = name;
  }

  speak() {
    console.log(`${this.name} makes a noise.`);
  }
}

class Dog extends Animal {
  constructor(name) {
    super(name); // здійснити виклик конструктора батьківського класу та передати йому ім'я в якості параметру
  }

  speak() {
    console.log(`${this.name} barks.`);
  }
}

const d = new Dog("Mitzie");
d.speak(); // Mitzie barks.

Якщо в підкласі існує конструктор, перед використанням this необхідно спочатку звернутися до super(). Ключове слово super може бути також використане для виклику методів батьківського класу, що відповідають поточному контексту.

class Cat {
  constructor(name) {
    this.name = name;
  }

  speak() {
    console.log(`${this.name} makes a noise.`);
  }
}

class Lion extends Cat {
  speak() {
    super.speak();
    console.log(`${this.name} roars.`);
  }
}

const l = new Lion("Fuzzy");
l.speak();
// Fuzzy makes a noise.
// Fuzzy roars.

Порядок оцінки

  • Спочатку оцінюється умовний блок extends, якщо він існує. Він має представляти собою відповідну конструкторську функцію або null; в іншому випадку буде викликано TypeError.
  • Витягується метод конструктора та замінюється стандартною реалізацією, якщо конструктор відсутній. Однак цей крок невидимий, оскільки визначення конструктора є лише методом.
  • Ключі властивостей елементів класу розглядаються послідовно. Якщо ключ властивості обчислюється, виконується вираз зі значенням this, яке відповідає оточуючому класу, а не самому класу. Значення властивості залишаються незмінними.
  • Методи та аксесори впорядковуються відповідно до оголошення. Методи екземпляру й аксесори додаються до властивості prototype класу, а статичні — безпосередньо до класу. Приватні методи та аксесори зберігаються для пізнішого використання.
  • Клас ініціалізується з використанням prototype та extends, якщо вони вказані. При спробі доступу до імені класу в раніше зазначених кроках виникає ReferenceError, оскільки клас ще не готовий.
  • Значення елементів класу визначаються в порядку їхнього введення: — Для кожного екземпляра зберігається вираз ініціалізатора. — Цей вираз виконується під час створення екземпляра, в початковому конструкторі або перед завершенням виклику super(). — Для статичних полів відбувається аналогічний процес, з this вказівником на сам клас. — Статичні блоки ініціалізації обробляються так само.
  • Нарешті, клас повністю ініціалізований і готовий до використання як конструктор.
Нотатка:

Приватні особливості мають обмеження, що всі назви властивостей, визначених у одному класі, повинні бути унікальними. Усі інші публічні властивості не мають цього обмеження — у вас може бути декілька публічних властивостей з однаковими назвами, і остання перезапише попередні.

Синтаксис

class ClassName {
  constructor() { ... }
  method_1() { ... }
  method_2() { ... }
  method_3() { ... }
}

Переглядачі

Переглядач

49

45

9

36

13

Переглядач

49

49

45

9

Переглядач

6.0.0

1.0

Приклади


Ми можемо використовувати класи для створення ієрархій наслідування. Розглянемо клас Animal, з якого наслідується клас Dog.

Клас Dog наслідує властивості та методи класу Animal, але перевизначає метод sound(), щоб відобразити специфічну для собак поведінку.

class Animal {
  constructor(name) {
    this.name = name;
  }

  sound() {
    console.log(this.name + ' makes a sound');
  }
}

class Dog extends Animal {
  sound() {
    console.log(this.name + ' barks');
  }
}

const rex = new Dog('Rex');
rex.sound(); // Виведе "Rex barks"

JavaScript дозволяє нам використовувати приватні властивості в класах за допомогою #.

У цьому прикладі #balance є приватною властивістю, і її можна змінити тільки за допомогою методів в межах класу BankAccount. Це допомагає контролювати доступ до важливих даних.

class BankAccount {
  #balance = 0;

  constructor(initialBalance) {
    this.#balance = initialBalance;
  }

  deposit(amount) {
    this.#balance += amount;
  }

  withdraw(amount) {
    if (amount <= this.#balance) {
      this.#balance -= amount;
    } else {
      console.log('Insufficient funds in the account');
    }
  }

  getBalance() {
    return this.#balance;
  }
}

const account = new BankAccount(1000);
account.withdraw(200);
console.log(account.getBalance()); // Виведе "800"

Методи

constructor()
Ініціалізує екземпляр класу при його створенні.

Властивості

extends
Дозволяє класу успадковувати властивості та методи від іншого класу.
static
Визначає методи або властивості, які належать безпосередньо до класу, а не до його екземплярів.
super
Дозволяє викликати методи батьківського класу в дочірньому класі.