Классы в JavaScript

Класс — это универсальный, комплексный тип данных, состоящий из тематически единого набора «полей» (переменных более элементарных типов) и «методов» (функций для работы с этими полями). Упрощенно класс можно представить в виде шаблона, в соответствии с которым создаются экземпляры класса.

Класс является моделью информационной сущности с внутренним и внешним интерфейсами для оперирования своим содержимым (значениями полей). 

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

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

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

В JavaScript классы используют прототипно-ориентированное наследование.

Часто на практике необходимо создавать много объектов одного вида (с одинаковым набором полей), например, пользователей, товары и т.д.

JavaScript содержит набор встроенных объектов, но вы можете создавать свои объекты следующими способами:

  1. с помощью функции-"конструктора" объекта new Object() (где Object - именование функции-"конструктора");
  2. с помощью конструктора экземпляра класса new Object() (где Object - именование класса class);
  3. с помощью фигурных скобок {…} с необязательным списком свойств (литеральная нотация). 

Различают два варианта синтаксиса "class":

  1. class expression;
  2. class declaration.

Тело класса при использовании как class declaration,  так и class expression будет исполняться в строгом режиме.

Методы в классе не разделяются запятой, это приводит к синтаксической ошибке.

Синтаксис "class expression"

Class expression - это способ определения класса в ECMAScript 2015 (ES6).

Схожий с function expressions, class expressions может быть:

  • именованным (в этом случае его имя доступно только внутри класса);
  • неименованным.

Синтаксис сlass expression:

Особенности сlass expression:

  1. Можно опустить имя класса ([className] - "binding identifier"), что не допустимо в class declaration.
  2. Позволяет повторно объявить уже существующий класс и это не приведёт к ошибке типа, как при использовании class declaration.
  3. Свойство constructor() является опциональным.
  4. Результатом вызова оператора typeof на классах, сгенерированных при помощи class expression, всегда будет "function".

Пример простого анонимного class expression, на который можно сослаться с помощью переменной Foo (отсюда):

Пример именованного class expression (позволяет сослаться на конкретный класс внутри тела класса, имя будет доступно только внутри области видимости самого class expression):

Синтаксис "class declaration"

Синтаксис class declaration создаёт новый класс с данным именем на основе прототипного наследования.

В отличие от class expression, class declaration не позволяет снова объявить уже существующий класс, это приведёт к ошибке типа.

Синтаксис class declaration:

nameClass технически является функцией (той, которую мы определяем как constructor()), в то время как методы, геттеры и сеттеры записываются в nameClass.prototype.

Свойство prop не устанавливается в nameClass.prototype. Вместо этого оно создаётся оператором new перед запуском конструктора, это именно свойство объекта.

Работа конструкции class declaration:

  1. Создаёт функцию с именем nameClass, которая становится результатом объявления класса.
  2. Код функции берётся из метода constructor() (она будет пустой, если такого метода нет).
  3. Сохраняет все методы в nameClass.prototype.

Особенности сlass declaration:

  1. Переопределение класса с помощью class declaration вызовет ошибку типа.
  2. Свойство constructor() является опциональным.
  3. Результатом вызова оператора typeof на классах, сгенерированных при помощи class expression, всегда будет "function".

Class declaration не поднимается (в отличие от декларируемых функций).

Пример простого class declaration:

В примере сначала определяется класс с именем Polygon, затем он наследуется для создания класса Square

Оператор super() используется для вызова функций, принадлежащих родителю объекта. Может быть указан только в конструкторе constructor() и должен быть вызван до того, как будет использовано ключевое слово this.

Обратите внимание: super действует только внутри методов, например, greet: function() {} является "нормальным" свойством/функцией, а не методом, потому что он не следует синтаксису метода, и super выдаст ошибку (надо записать так: greet() {}, тогда super отработает без ошибок).

Попытка объявить класс дважды:

Та же ошибка будет вызвана, если класс уже был определён перед использованием class declaration:

Класс как аналог функции-конструктора

Перепишем класс Polygon как функцию-конструктор:

Отличия классов от функций-конструкторов:

  1. Функция, созданная с помощью class, помечена специальным внутренним свойством [[FunctionKind]]:"classConstructor".
  2. В отличие от обычных функций, конструктор класса вызывается с помощью new.
  3. Методы класса являются неперечислимыми (определение класса устанавливает флаг enumerable в false для всех методов в prototype, поэтому, например, цикл for...in их не переберёт).
  4. Классы всегда используют 'use strict' (весь код внутри класса автоматически исполняется в строгом режиме).

Создание классов динамически («по запросу»)

Допускается динамическое (по запросу, во время выполнения кода) создание классов:

Get и set (геттеры и сеттеры) в классах

Как и в литеральных объектах, в классах можно объявлять вычисляемые свойства, геттеры/сеттеры и т.д., например:

После объявления класса геттеры/сеттеры добавляются в User.prototype, например:

Пример с вычисляемым свойством в квадратных скобках [...]:

 

Добавить комментарий

Этот сайт использует Akismet для борьбы со спамом. Узнайте, как обрабатываются ваши данные комментариев.