Skip to content

13. Класи

Image

Тут ми вводимо класи ECMAScript 6. Спочатку ми покажемо, що функції вже можна використовувати як класи.

13.1. скрипт [class-00]

Наступний скрипт демонструє незвичайне використання функцій. Тут їх використовують як об’єкти.


'use strict';
// функцію можна використовувати як об’єкт

// порожня оболонка
function f() {

}
//, якому ззовні присвоюються властивості
f.prop1 = "val1";
f.show = function () {
  console.log(this.prop1);
}
// використання f
f.show();

// функція g, що працює як клас
function g() {
  this.prop2 = "val2";
  this.show = function () {
    console.log(this.prop2);
  }
}
// інстанціювання функції за допомогою [new]
new g().show();

Коментарі

  • рядки 5–7: тіло функції f не визначає жодних властивостей;
  • рядки 9–12: властивості функції f задаються ззовні;
  • рядок 14: використання функції (об’єкта) f. Зверніть увагу, що ми пишемо не [f()], а просто [f]. Це нотація об’єкта;
  • рядки 17–22: визначається функція [g] так, ніби це клас із властивостями та методами;
  • рядок 24: функція [g] інстанціюється за допомогою [new g()];

Результати виконання


[Running] C:\myprograms\laragon-lite\bin\nodejs\node-v10\node.exe -r esm "c:\Data\st-2019\dev\es6\javascript\classes\class-00.js"
val1
val2

ES6 запровадила поняття класу, що відтепер дозволяє нам уникати використання функцій для створення класів.

13.2. скрипт [class-01]

Скрипт [class-01] представляє клас [Personne]:


// клас
class Personne {

  // конструктор
  constructor(nom, prénom, âge) {
    this.nom = nom;
    this.prénom = prénom;
    this.âge = âge;
  }

  // методи getter та setter
  get nom() {
    return this._nom;
  }
  set nom(value) {
    this._nom = value;
  }

  get prénom() {
    return this._prénom;
  }
  set prénom(value) {
    this._prénom = value;
  }

  get âge() {
    return this._âge;
  }
  set âge(value) {
    this._âge = value;
  }

  // toString у JSON
  toString() {
    return JSON.stringify(this);
  }
}

// виклик класу
function main() {
  const personne = new Personne("Poirot", "Hercule", 66);
  console.log("personne=", personne.toString(), typeof (personne), personne instanceof (Personne));
}

// виклик методу main
main();

Коментарі

  • рядок 2: ключове слово [class] позначає клас;
  • рядки 5–9: ключове слово [constructor] позначає конструктор класу. Він може бути лише один. Він слугує для створення та ініціалізації екземпляра класу. Зверніть увагу, що оголошення властивостей [nom, prénom, âge] відсутнє;
  • рядки 11–36: властивості класу. Тут містяться елементи, які ми вже розглядали в розділі про об’єкти 4 на сторінці 44. Відрізняється лише синтаксис;
  • рядок 41: створення об’єкта типу [Personne]. Відтепер об’єкт [personne] використовується як літеральний об’єкт. [typeof (personne)] дорівнює «object», а вираз [personne instanceof (Personne)] є істинним. Отже, можна визначити точний тип екземпляра класу;

Результати виконання


[Running] C:\myprograms\laragon-lite\bin\nodejs\node-v10\node.exe -r esm "c:\Data\st-2019\dev\es6\javascript\classes\class-01.js"
personne= {"_nom":"Poirot","_prénom":"Hercule","_âge":66} object true

13.3. скрипт [class-02]

Цей скрипт демонструє можливість успадкування класу за допомогою ключового слова [extends].

Спочатку виділяємо клас [Personne] у модуль [Personne.js]:


// клас
class Personne {

  // конструктор
  constructor(nom, prénom, âge) {
    this.nom = nom;
    this.prénom = prénom;
    this.âge = âge;
  }

  // методи getter та setter
  get nom() {
    return this._nom;
  }
  set nom(value) {
    this._nom = value;
  }

  get prénom() {
    return this._prénom;
  }
  set prénom(value) {
    this._prénom = value;
  }

  get âge() {
    return this._âge;
  }
  set âge(value) {
    this._âge = value;
  }

  // toString у JSON
  toString() {
    return JSON.stringify(this);
  }
}
// експорт класу
export default Personne;
  • рядок 39: ми експортуємо клас [Personne], щоб інші скрипти могли його імпортувати;

Скрипт [class-02] створює клас [Enseignant], похідний від класу [Personne]:


// імпорт
import Personne from './Personne';

// клас
class Enseignant extends Personne {

  // конструктор
  constructor(nom, prénom, âge, discipline) {
    super(nom, prénom, âge);
    this.discipline = discipline;
  }

  // методи getter та setter
  get discipline() {
    return this._discipline;
  }
  set discipline(value) {
    this._discipline = value;
  }

}

// виклик класу
function main() {
  const enseignant = new Enseignant("Poirot", "Hercule", 66, "détective");
  console.log("enseignant=", enseignant.toString(), typeof (enseignant), enseignant instanceof Enseignant);
}

// виклик main
main();

Коментарі

  • рядок 2: імпортується клас [Personne] з модуля [Personne.js], який знаходиться в тій самій папці, що й [class-02];
  • рядок 5: клас [Enseignant] розширює (успадковує) клас [Personne] за допомогою ключового слова [extends]: він додає до нього властивість [_discipline] із відповідними методами getter та setter;
  • рядки 8–11: конструктор класу [Enseignant] отримує чотири значення для ініціалізації чотирьох властивостей класу;
  • рядок 9: ключове слово [super] викликає конструктор батьківського класу [Personne], який, таким чином, ініціалізує властивості [_nom, _prénom, _âge];
  • рядок 10: ініціалізується властивість [_discipline], що належить класу [Enseignant];
  • рядки 14–19: геттер і сеттер властивості [_discipline];
  • рядок 25: створюється об’єкт типу [Enseignant];
  • рядок 26: використовується метод [enseignant.toString()]. Клас [Enseignant] не має цього методу. Тоді автоматично використовується метод його батьківського класу. Цей метод робить вираз [JSON.stringify(this)], де [this] тут буде об’єктом [Enseignant], а не об’єктом [Personne]. У об’єктно-орієнтованому програмуванні це називається поліморфізмом класів. Це складне поняття для JavaScript, який не є об’єктно-орієнтованою мовою. Проте JavaScript у цьому випадку робить те, чого від нього очікують: він правильно відображає вчителя;

Результати виконання такі:


[Running] C:\myprograms\laragon-lite\bin\nodejs\node-v10\node.exe -r esm "c:\Data\st-2019\dev\es6\javascript\classes\class-02.js"
enseignant= {"_nom":"Poirot","_prénom":"Hercule","_âge":66,"_discipline":"détective"} object true
  • рядок 2: JavaScript правильно розпізнає, що змінна [enseignant] має тип [Enseignant];

13.4. скрипт [class-03]

Скрипт [class-03] демонструє, що дочірній клас може перевизначати властивості та методи свого батьківського класу. Тут ми перевизначаємо метод [toString] батьківського класу:


// імпорти
import Personne from './Personne';

// клас
class Enseignant extends Personne {

  // конструктор
  constructor(nom, prénom, âge, discipline) {
    super(nom, prénom, âge);
    this.discipline = discipline;
  }

  // методи getter та setter
  get discipline() {
    return this._discipline;
  }
  set discipline(value) {
    this._discipline = value;
  }

  // перевизначення toString
  toString() {
    return "[Enseignant]" + JSON.stringify(this);
  }
}

// виклик класу
function main() {
  const enseignant = new Enseignant("Poirot", "Hercule", 66, "détective");
  console.log("enseignant=", enseignant.toString(), typeof (enseignant), enseignant instanceof Enseignant);
}

// виклик функції main
main();

Результати виконання такі:


[Running] C:\myprograms\laragon-lite\bin\nodejs\node-v10\node.exe -r esm "c:\Data\st-2019\dev\es6\javascript\classes\class-03.js"
enseignant= [Enseignant]{"_nom":"Poirot","_prénom":"Hercule","_âge":66,"_discipline":"détective"} object true

13.5. скрипт [class-04]

Скрипт [class-04] знову демонструє поліморфізм у дії: там, де функція очікує формальний параметр типу [Personne], можна передати похідний тип, такий як [Enseignant]. Адже завдяки похідності тип [Enseignant] має всі атрибути типу [Personne].

Спочатку ми виділяємо тип [Enseignant] у модуль [Enseignant.js]:


// імпорт
import Personne from './Personne';

// клас
class Enseignant extends Personne {

  // конструктор
  constructor(nom, prénom, âge, discipline) {
    super(nom, prénom, âge);
    this.discipline = discipline;
  }

  // методи getter та setter
  get discipline() {
    return this._discipline;
  }
  set discipline(value) {
    this._discipline = value;
  }

}

// експорт класу
export default Enseignant;
  • рядок 24: клас [Enseignant] експортується, щоб інші скрипти могли його імпортувати;

Скрипт [class-04] має такий вигляд:


// імпорт
import Enseignant from './Enseignant';
import Personne from './Personne';

// функція, що приймає людину як параметр
function show(personne) {
  // у всіх випадках
  console.log("paramètre=", personne.toString(), typeof (personne));
  // екземпляр класу «Людина»
  if (personne instanceof Personne) {
    console.log("personne=", personne.toString());
  }
  // екземпляр класу «Викладач»
  if (personne instanceof Enseignant) {
    console.log("enseignant=", personne.toString());
  }
}

// виклик функції show з параметром «викладач»
show(new Enseignant("Poirot", "Hercule", 66, "détective"));
show(new Personne("Marple", "Miss", 70));
  • рядок 6: функція [show] очікує тип [Personne] або його похідний;
  • рядок 8: виводиться рядок параметра та його тип. Ми побачимо [object];
  • рядки 10–16: можна визначити, чи це тип [Personne], чи тип [Enseignant]. Отже, код можна адаптувати до фактичного типу параметра;

Результати виконання такі:


[Running] C:\myprograms\laragon-lite\bin\nodejs\node-v10\node.exe -r esm "c:\Data\st-2019\dev\es6\javascript\classes\class-04.js"
paramètre= {"_nom":"Poirot","_prénom":"Hercule","_âge":66,"_discipline":"détective"} object
personne= {"_nom":"Poirot","_prénom":"Hercule","_âge":66,"_discipline":"détective"}
enseignant= {"_nom":"Poirot","_prénom":"Hercule","_âge":66,"_discipline":"détective"}
paramètre= {"_nom":"Marple","_prénom":"Miss","_âge":70} object
personne= {"_nom":"Marple","_prénom":"Miss","_âge":70}
  • рядки 4 та 6: JavaScript правильно розпізнає тип екземплярів класу;