Javascript, класи

Зазвичай екземпляри класу вимагають додаткової ініціалізації, тому зазвичай визначається функція, яка створює і ініціалізує нові об'єкти. У наступному прикладі демонструється така функція: вона визначає об'єкт-прототип класу, що представляє діапазон значень, а також «фабричну» функцію, яка створює і ініціалізує нові екземпляри класу:

У цьому прикладі є кілька цікавих моментів, які слід відзначити особливо. Тут визначається фабрична функція range (), яка використовується для створення нових об'єктів range.

Відзначте, що функція range () визначає властивості from і to для кожного об'єкта range. Ці не загальні, що не успадковані властивості визначають унікальну інформацію для кожного окремого об'єкта range. Нарешті, зверніть увагу, що всі загальні, успадковані методи від rangeObj використовують властивості from і to і посилаються на них за допомогою ключового слова this, що вказує на об'єкт, щодо якого викликаються ці методи. Такий спосіб використання this є фундаментальною характеристикою методів будь-якого класу.

конструктори

Конструктори викликаються за допомогою ключового слова new. Застосування ключового слова new при виклику конструктора автоматично створює новий об'єкт, тому конструктору залишається тільки форматувати властивості цього нового об'єкта. Важливою особливістю виклику конструктора є використання властивості prototype конструктора в якості прототипу нового об'єкта. Це означає, що всі об'єкти, створені за допомогою одного конструктора, успадковують один і той же об'єкт-прототип і, відповідно, є членами одного і того ж класу.

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

Має сенс детально порівняти ці два приклади і відзначити відмінності між цими двома способами визначення класів. По-перше, зверніть увагу, що при перетворенні в конструктор фабрична функція range () була перейменована в Range (). Це звичайна угода з оформлення: функції-конструктори в деякому сенсі визначають класи, а імена класів починаються з великої символів. Імена звичайних функцій і методів починаються з малої символів.

Далі відзначте, що конструктор Range () викликається (в кінці прикладу) з ключовим словом new, тоді як фабрична функція range () викликається без нього. У першому прикладі для створення нового об'єкта використовувався виклик звичайної функції, а в другому - виклик конструктора. Оскільки конструктор Range () викликається з ключовим словом new, відпадає необхідність викликати функцію inherit () або робити які-небудь інші дії зі створення нового об'єкта. Новий об'єкт створюється автоматично перед викликом конструктора і доступний в конструкторі як значення this. Конструктору Range () залишається лише форматувати його.

Конструктори навіть не повинні повертати новостворений об'єкт. Вираз виклику конструктора автоматично створює новий об'єкт, викликає конструктор як метод цього об'єкта і повертає об'єкт. Той факт, що виклик конструктора настільки відрізняється від виклику звичайної функції, є ще однією причиною, чому конструкторам прийнято давати імена, що починаються з заголовного символу. Конструктори призначені для виклику у вигляді конструкторів, з ключовим словом new, і зазвичай при виклику у вигляді звичайних функцій вони не здатні коректно виконувати свою роботу. Угода по іменування конструкторів, який забезпечує візуальне відміну імен конструкторів від імен звичайних функцій, допомагає програмістам не забувати використовувати ключове слово new.

Ще одна важлива відмінність полягає в способі іменування об'єкта-прототипу. У першому прикладі прототипом був об'єкт rangeObj. Це було зручне, описову назву, але в значній мірі довільне. У другому прикладі прототипом є властивість Range.prototype, і це ім'я є обов'язковим. Вираз виклику конструктора Range () автоматично використовує властивість Range.prototype як прототип нового об'єкта Range.

Нарешті, зверніть також увагу на однакові фрагменти прикладів - в обох класах методи об'єкта range визначаються і викликаються однаковим способом.

властивість constructor

У другому прикладі властивості Range.prototype присвоювався новий об'єкт, що містить методи класу. Хоча було зручно визначити методи як властивості єдиного об'єкта-литерала, але при цьому абсолютно не було необхідності створювати новий об'єкт.

Наявність зумовленого об'єкта-прототипу з властивістю constructor означає, що об'єкти зазвичай успадковують властивість constructor, яке посилається на їхні конструктори. Оскільки конструктори грають роль ідентифікаторів класів, властивість constructor визначає клас об'єкта:

Ці взаємозв'язки між функцією-конструктором, її прототипом, зворотнім посиланням з прототипу на конструктор і екземплярами, створеними за допомогою конструктора, ілюструються наступною діаграмою:

Javascript, класи

Зверніть увагу, що в якості прикладу для цієї діаграми був узятий наш конструктор Range (). Однак в дійсності клас Range заміщає зумовлений об'єкт Range.prototype своїм власним. А новий об'єкт-прототип не має властивості constructor. З цієї причини екземпляри класу Range, як випливає з визначення, не мають властивості constructor. Вирішити цю проблему можна, явно додавши конструктор в прототип:

Інший типовий спосіб полягає в тому, щоб використовувати зумовлений об'єкт-прототип, який вже має властивість constructor, і додавати методи в нього:

Схожі статті