Как обратиться к полю класса

от admin

ООП. Классы

С внедрением стандарта ES2015 (ES6) в JavaScript появился новый способ определения объектов — с помощью классов. Класс представляет описание объекта, его состояния и поведения, а объект является конкретным воплощением или экземпляром класса.

Опредление класса

Для определения класса используется ключевое слово class :

После слова class идет название класса (в данном случае класс называется Person), и затем в фигурных скобках определяется тело класса.

Это наиболее расспространенный способ определения класса. Но есть и другие способы. Так, также можно определить анонимный класс и присвоить его переменной или константе:

В принципе мы можем создать и неанонимный класс и присвоить его переменной или константе:

Создание объектов

Класс — это общее представление некоторых сущностей или объектов. Конкретным воплощением этого представления, класса является объект. И после определения класса мы можем создать объекты класса с помощью конструктора:

Для создания объекта с помощью конструктора сначала ставится ключевое слово new . Затем собственно идет вызов конструктора — по сути вызов функции по имени класса. По умолчанию классы имеют один конструктор без параметров. Поэтому в данном случае при вызове конструктора в него не передается никаких аргументов.

Стоит отметить, что в отличие от функций, чтобы использовать класс, его надо сначала определить. Например, в следующем коде мы получим ошибку, так как пытаемся использовать класс до его определения:

Если определение класса присвоено переменной или константе, то мы можем использовать имя этой переменной/константы для создания объектов класса:

Выше в коде несмотря на то, что мы используем вызов new User() , в реальности создаваемый объект будет представлять класс Person.

Пример создания объекта анонимного класса:

Поля и свойства класса

Для хранения данных или состояния объекта в классе используются поля и свойства.

Итак, выше был определен класс Person, который представлял человека. У человека есть отличительных признаков, например, имя и возраст. Определим в классе Person поля для хранения этих данных:

Определение поля фактически просто представляет его название:

Так, здесь определено поле name для хранения имени человека, и поле age для хранения возраста человека.

После создания объекта класса мы можем обратиться к этим полям. Для этого после имени объекта через точку указывается имя поля:

В примере выше поля класса также можно назвать свойствами . По сути свойства представляют доступные извне или публичные поля класса. Дальше мы подробно разберем, когда поля бывают непубличные, то есть недоступными извне. Но пока стоит понимать, что свойства и публичные поля — это одно и то же. И в примере выше поля name и age также можно назвать свойствами.

При необходимости мы можем присвоить полям некоторые начальные значения:

Поведение класса и его методы

Кроме хранения данных, которые определяют состояние объекта, класс может иметь методы, которые определяют поведение объекта — действия, которые выполняет объект. Например, определим в классе Person пару методов:

Здесь определен метод move() , который представляет условное передвижение человека. В качестве параметра метод принимает место, к которому идет человек. Второй метод — eat() — представляет условный процесс питания.

Обращение к полям и методам внутри класса. Слово this

Что если мы хотим в методах класса обратиться к полям класса или к другим его методам? В этом случае перед именем поля/свойства или метода указывается ключевое слово this , которое в данном случае указывает на текущий объект.

Например, определим метод, который выводит информацию об объекте:

Определение конструктора

Для создания объекта класса используется конструктор:

Вызов конструктора по умолчанию, который есть в классах, фактически представляет вызов метода, который имеет то же название, что и класс, и возвращает объект этого класса.

Но также мы можем определить в классах свои конструкторы:

Конструктор определяется с помощью метода с именем constructor . По сути это обычный метод, который может принимать параметры. В данном случае конструктор просто выводит на консоль некоторое сообщение. Соответственно при выполнении строки

Мы увидим в консоли браузера соответствующее сообщение.

Как правило, цель конструктора — инициализация объекта некоторыми начальными данными:

Здесь конструктор принимает два параметра и передает их значения полям класса. Соответственно при создании объекта мы можем передать в конструктор соответствующие значения для этих параметров:

Стоит отметить, что в примере выще определения полей класса избыточно. Обращение в конструкторе к полям через this фактически будет аналогично их определению, и в данном случае мы можем убрать определение полей:

Обращение к полям класса по имени

Что необходимо сделать чтобы можно инициализировать поля экземпляр класса через instance[«Age»] = 5; И возможно ли такое?

Bald's user avatar

Это можно сделать с помощью индексатора ( [] ) и рефлексии. Примерный код:

Данный код работает для всех экземплярных полей. Если вам надо устанавливать в т.ч. и статические поля — нужно изменить код. Также по-хорошему нужно добавить валидацию (например, что указано имя существующего поля, или что тип устанавливаемого значения соответствует типу поля) и кэширование списка полей (чтобы запрашивать их только один раз).

Хотя лучше всего таки использовать сами поля или свойства. Или заменить ваш класс на словарь, где ключом будем являться имя поля/свойства.

Статические переменные

Когда класс загружается в память, для него сразу создается статический объект класса. Этот объект хранит статические переменные класса (статические поля класса). Статический объект класса существует, даже если не был создан ни один обычный объект класса.

Когда мы описываем переменные в классе, мы указываем, будут ли эти переменные созданы всего один раз или же нужно создавать их копии для каждого объекта. По умолчанию создаётся новая копия переменной для каждого объекта.

Статическая (static) же переменная привязана к статическому объекту класса и всегда существует в единственном экземпляре.

Чтобы создать статическую переменную класса, нужно перед ее именем написать ключевое слово static . Общий вид объявления статической переменной такой:

Если статической переменной не присвоить стартовое значение, она инициализируется значением по умолчанию:

Тип Значение по умолчанию
(то же самое, что и )
и любые классы
Код Примечание

Обращаться к статической переменной в ее классе можно просто по имени. Если обращение идет из другого класса, то перед именем статической переменной нужно писать имя класса.

JavaScript: полное руководство по классам

В JavaScript используется модель прототипного наследования: каждый объект наследует поля (свойства) и методы объекта-прототипа.

Классов, используемых в Java или Swift в качестве шаблонов или схем для создания объектов, в JavaScript не существует. В прототипном наследовании есть только объекты.

Прототипное наследование может имитировать классическую модель наследования от классов. Для этого в ES6 было представлено ключевое слово class: синтаксический сахар для прототипного наследования.

В данной статье мы научимся работать с классами: определять классы, их частные (приватные) и открытые (публичные) поля и методы, а также создавать экземпляры.

1. Определение: ключевое слово class

Для определения класса используется ключевое слово class:

Такой синтаксис называется объявлением класса.

Класс может не иметь названия. С помощью выражения класса можно присвоить класс переменной:

Классы можно экспортировать в виде модулей. Вот пример экспорта по умолчанию:

А вот пример именованного экспорта:

Классы используются для создания экземпляров. Экземпляр — это объект, содержащий данные и логику класса.

Экземпляры создаются с помощью оператора new: instance = new Class().

Вот как создать экземпляр класса User:

2. Инициализация: constructor()

constructor(param1, param2, . ) — это специальный метод внутри класса, служащий для инициализации экземпляра. Это то место, где устанавливаются начальные значения полей экземпляра и осуществляется его настройка.

В следующем примере конструктор устанавливает начальное значение поля name:

Конструктор принимает один параметр — name, который используется для установки начального значения поля this.name.

this в конструкторе указывает на создаваемый экземпляр.

Аргумент, используемый для создания экземпляра класса, становится параметром его конструктора:

Параметр name внутри конструктора имеет значение ‘Печорин’.

Если не определить собственный конструктор, будет создан стандартный конструктор, представляющий собой пустую функцию, не влияющую на экземпляр.

3. Поля

Поля класса — это переменные, содержащие определенную информацию. Поля могут быть разделены на две группы:

  1. Поля экземпляров класса
  2. Поля самого класса (статические)
  1. Открытые (публичные): поля доступны как внутри класса, так и в экзмеплярах
  2. Частные (приватные): поля доступны только внутри класса
Читать:
Как преобразовать сайт в pdf

3.1. Открытые поля экземпляров класса

Выражение this.name = name создает поле экземпляра name и присваивает ему начальное значение.

Доступ к этому полю можно получить с помощью аксессора свойства:

В данном случае name — открытое поле, поскольку оно доступно за пределами класса User.

При неявном создании полей внутри конструктора, сложно получить список всех полей. Для этого поля нужно извлекать из конструктора.

Лучшим способом является явное определение полей класса. Неважно, что делает конструктор, экземпляр всегда имеет одинаковый набор полей.

Предложение по созданию полей класса позволяет определять поля внутри класса. Кроме того, здесь же можно присваивать полям начальные значения:

Изменим код класса User, определив в нем открытое поле name:

Такие открытые поля являются очень наглядными, быстрый взгляд на класс позволяет понять структуру его данных.

Более того, поле класса может быть инициализировано в момент определения:

На доступ к открытым полям и их изменение нет ограничений. Читать и присваивать значения таким полям можно в конструкторе, методах и за пределами класса.

3.2. Частные поля экземпляров класса

Инкапсуляция позволяет скрывать внутренние детали реализации класса. Тот, кто использует инкапсулированный класс, опирается на публичный интерфейс, не вдаваясь в подробности реализации класса.

Такие классы проще обновлять при изменении деталей реализации.

Хорошим способом скрыть детали является использование частных полей. Такие поля могут быть прочитаны и изменены только внутри класса, которому они принадлежат. За пределами класса частные поля недоступны.

Для того, чтобы сделать поле частным, перед его названием следует поставить символ #, например, #myPrivateField. При обращении к такому полю всегда должен использоваться указанный префикс.

Сделаем поле name частным:

#name — частное поле. Доступ к нему можно получить только внутри класса User. Это позволяет сделать метод getName().

Однако, при попытке получить доступ к #name за пределами класса User будет выброшена синтаксическая ошибка: SyntaxError: Private field ‘#name’ must be declared in an enclosing class.

3.3. Открытые статические поля

В классе можно определить поля, принадлежащие самому классу: статические поля. Такие поля используются для создания констант, хранящих нужную классу информацию.

Для создания статических полей используется ключевое слово static перед названием поля: static myStaticField.

Добавим новое поле type для определения типа пользователя: администратора или обычного. Статические поля TYPE_ADMIN и TYPE_REGULAR — константы для каждого типа пользователей:

Для доступа к статическим полям следует использовать название класса и название свойства: User.TYPE_ADMIN и User.TYPE_REGULAR.

3.4. Частные статические поля

Иногда статические поля также являются частью внутренней реализации класса. Для инкапсуляции таких полей можно сделать их частными.

Для этого следует перед названием поля поставить префикс #: static #myPrivateStaticFiled.

Предположим, что мы хотим ограничить количество экземпляров класса User. Для сокрытия информации о количестве экземпляров можно создать частные статические поля:

Статическое поле User.#MAX_INSTANCES определяет допустимое количество экземпляров, а User.#instances — количество созданных экземпляров.

Эти частные статические поля доступны только внутри класса User. Ничто из внешнего мира не может повлиять на ограничения: в этом заключается одно из преимуществ инкапсуляции.

Прим. пер.: если ограничить количество экземпляров одним, получится интересная реализация шаблона проектирования «Одиночка» (Singleton).

4. Методы

Поля содержат данные. Возможность изменять данные обеспечивается специальными функциями, являющимися частью класса: методами.

JavaScript поддерживает как методы экземпляров класса, так и статические методы.

4.1. Методы экземпляров класса

Методы экземпляра класса могут изменять его данные. Методы экземпляра могут вызывать другие методы экземпляра, а также статические методы.

Например, определим метод getName(), возвращающий имя пользователя:

В методе класса, также как и в конструкторе, this указывает на создаваемый экземпляр. Используйте this для получения данных экземпляра: this.field, или для вызова методов: this.method().

Добавим новый метод nameContains(str), принимающий один аргумент и вызывающий другой метод:

nameContains(str) — метод класса User, принимающий один аргумент. Он вызывает другой метод экземпляра getName() для получения имени пользователя.

Метод также может быть частным. Для того, чтобы сделать метод частным следует использовать префикс #.

Сделаем метод getName() частным:

#getName() — частный метод. Внутри метода nameContains(str) мы вызываем его так: this.#getName().

Будучи частным, метод #getName() не может быть вызван за пределами класса User.

4.2. Геттеры и сеттеры

Геттеры и сеттеры — это аксессоры или вычисляемые свойства. Это методы, имитирующие поля, но позволяющие читать и записывать данные.

Геттеры используются для получения данных, сеттеры — для их изменения.

Для установки запрета на присвоение полю name пустой строки, обернем частное поле #nameValue в геттер и сеттер:

4.3. Статические методы

Статические методы — это функции, принадлежащие самому классу. Они определяют логику класса, а не его экземпляров.

Для создания статического метода используется ключевое слово static перед названием метода: static myStaticMethod().

При работе со статическими методами, следует помнить о двух простых правилах:

  1. Статический метод имеет доступ к статическим полям
  2. Он не имеет доступа к полям экземпляров

isNameTaken() — статический метод, использующий частное статическое поле User.#takenNames для определения использованных имен.

Статические методы также могут быть частными: static #myPrivateStaticMethod(). Такие методы могут вызываться только внутри класса.

5. Наследование: extends

Классы в JavaScript поддерживают наследование с помощью ключевого слова extends.

В выражении class Child extends Parent < >класс Child наследует от класса Parent конструктор, поля и методы.

Создадим дочерний класс ContentWriter, расширяющий родительский класс User:

ContentWriter наследует от User конструктор, метод getName() и поле name. В самом ContentWriter определяется новое поле posts.

Обратите внимание, что частные поля и методы родительского класса не наследуются дочерними классами.

5.1. Родительский конструктор: super() в constructor()

Для того, чтобы вызвать конструктор родительского класса в дочернем классе, следует использовать специальную функцию super(), доступную в конструкторе дочернего класса.

Пусть конструктор ContentWriter вызывает родительский конструктор и инициализирует поле posts:

super(name) в дочернем классе ContentWriter вызывает конструктор родительского класса User.

Обратите внимание, что в дочернем конструкторе перед использованием ключевого слова this вызывается super(). Вызов super() «привязывает» родительский конструктор к экземпляру.

5.2. Родительский экземпляр: super в методах

Для того, чтобы получить доступ к родительскому методу внутри дочернего класса, следует использовать специальное сокращение super:

getName() дочернего класса ContentWriter вызывает метод getName() родительского класса User.

Это называется переопределением метода.

Обратите внимание, что super можно использовать и для статических методов родительского класса.

6. Проверка типа объекта: instanceof

Выражение object instanceof Class определяет, является ли объект экземпляром указанного класса.

Оператор instanceof полиморфичен: он исследует всю цепочку классов.

Что если нам нужно определить конкретный класс экземпляра? Для этого можно использовать свойство constructor:

7. Классы и прототипы

Надо сказать, что синтаксис классов — это хорошая абстракция над прототипным наследованием. Для использования классов не нужно обращаться к прототипам.

Однако, классы являются лишь надстройкой над прототипным наследованием. Любой класс — это функция, создающая экземпляр при вызове конструктора.

Следущие два примера идентичны.

Поэтому для понимания классов требуется хорошее знание прототипного наследования.

8. Доступность возможностей классов

Возможности классов, представленные в данной статье, распределены между спецификацией ES6 и предложениями, находящимися на третьей стадии рассмотрения:

Прим. пер.: по данным Can I use поддержка частных полей классов на сегодняшний день составляет 68%.

9. Заключение

Классы в JavaScript используются для инициализации экземпляров с помощью конструктора, определения их полей и методов. С помощью ключевого слова static можно определять поля и методы самого класса.

Наследование реализуется с помощью ключевого слова extends. Ключевое слово super позволяет получить доступ к родительскому классу из дочернего.

Для того, чтобы воспользоваться преимуществами инкапсуляции, т.е. скрыть внутренние детали реализации, сделайте поля и методы частными. Названия таких полей и методов должны начинаться с символа #.

Похожие статьи